目录

TCP 简 介

TCP VS UDP

TCP VS HTTP

TCP 3次握手与4次挥手

TCP 与 Java

TCP 服务器端编码

TCP 客户端端编码

连接超时与读取超时

网络编程


TCP 简 介

1、TCP(Transmission Control Protocol) 是 socket 上的一种提供可靠的数据传输的通信协议——传输控制协议

2、TCP 只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。就像操作系统会提供标准的编程接口,比如 Win32 编程接口一样,TCP 也必须对外提供编程接口,这就是 Socket 编程接口

3、TCP/IP 协议是一个协议簇,包括应用层,传输层,网络层,网络访问层,之所以命名为TCP/IP协议,因为TCP、IP协议是两个很重要的协议。TCP 协议只是 TCP/IP 协议簇下的其中一个。

4、通过 IP 协议并不能清楚地了解到数据包是否顺利地发送给目标计算机,而使用 TCP 协议,它将数据包成功发送给目标计算机后,会要求发送一个确认,如果在某个时间内没有收到确认,TCP将重新发送数据包。

5、Socket(套接字) 实际上是对 TCP 协议的封装,Socket 本身并不是协议,而是一个调用接口(API),通过 Socket 才能使用 TCP协议

6、Socket编程基本就是listen,accept以及send,write等几个基本的操作 ,Java JDK 中 Socket 编程的 API 都在 java.net包中

TCP VS UDP

1、TCP(Transmission Control Protocol) 可以保证数据的正确性和可靠性,UDP 则允许数据丢失

2、TCP 和 UDP(User Datagram Protocol   用户数据报协议)同属于传输层,共同架设在IP层(网络层)之上

3、IP 层主要负责节点之间(End to End)的数据包传送,这里的节点是一台网络设备,比如计算机,只负责把数据送到节点,而不能区分上面的不同应用,所以 TCP 和 UDP 协议在其基础上加入了端口信息,端口于是标识的是一个节点上的一个应用

4、除了增加端口信息,UPD 协议基本就没有对 IP 层的数据进行任何的处理了,而TCP协议还加入了更加复杂的传输控制,比如滑动的数据发送窗口(Slice Window),以及接收确认和重发机制,以达到数据的可靠传送。

5、采用 UDP 的 QQ 比采用 TCP 传输协议的 MSN 传输文件要快,但并不能说 QQ 的通信是不安全的,因为程序员可以把确认、验证的工作交给应用程序来做

6、TCP 协议提供了可靠的数据传输,但是其拥塞控制、数据校验、重传机制的网络开销很大,不适合实时通信,所以选择开销很小的 UDP 协议来传输数据

对比项

TCP

UDP

说明

对系统要求

较多

程序结构

较复杂

简单

UDP是流模式、数据报模式

数据准确性

UDP可能丢包

数据顺序

保证顺序

不保证顺序

数据大小

较大

短消息

客户端数目

较少

大量

响应速度

较慢

网络负担

较大

7、UDP 就像发短信,只管发出去,至于对方是不是空号(网络不可到达)能不能收到(丢包)等并不关心;TCP 就像打电话,双方要通话,首先,要确定对方是不是开机(网络可以到达),然后要确定是不是没有信号(网络可以到达),然后还需要对方接听(通信链接)。

TCP VS HTTP

1、TPC 协议是传输层协议,主要解决数据如何在网络中传输,而 HTTP 是应用层协议,主要解决如何包装数据

2、传输数据时,可以只使用(传输层)TCP 协议,但是这样就没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如 HTTP、FTP、TELNET 等,也可以自己定义应用层协议。WEB 使用 HTTP 协议作应用层协议,以封装 HTTP 文本信息,然后使用 TCP 做传输层协议将它发到网络上。

3、套接字(Socket)是通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:

1)连接使用的协议

2)本地主机的IP地址

3)本地进程的协议端口

4)远地主机的IP地址

5)远地进程的协议端口

4、应用层通过传输层进行数据通信时,TCP 会遇到同时为多个应用程序进程提供并发服务的问题,为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与 TCP/IP 协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket 接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

TCP 3次握手与4次挥手

1、TCP 是面向连接的,虽然说网络的不安全不稳定特性决定了多少次握手都不能保证连接的可靠性,但 TCP 的三次握手在很大程度上保证了连接的可靠性。

2、建立起一个 TCP 连接需要经过“三次握手”

第一次握手:客户端发送 syn (Synchronization:同步) 包 (syn=j) 到服务器,并进入SYN_SEND 状态,等待服务器确认

第二次握手:服务器收到 syn 包,必须确认客户的 SYN (ack=j+1),同时自己也发送一个 SYN包(syn=k),即SYN+ACK (Acknowledge:承认)包,此时服务器进入SYN_RECV(Receive:接收)状态;

第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(Established:建立、确立) 状态,完成三次握手。

3、握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP 连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

4、服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手” 。

TCP 与 Java

1、协议相当于相互通信的程序间达成的一种约定,它规定了分组报文的结构、交换方式、包含的意义以及怎样对报文所包含的信息进行解析

2、TCP/IP 协议族有 IP 协议、TCP 协议和 UDP 协议

3、现在 TCP/IP 协议族中的主要 socket 类型为流套接字(使用TCP协议)和数据报套接字(使用UDP协议)

4、TCP 协议提供面向连接的服务,通过它建立的是可靠地连接,Java为 TCP 协议提供了两个类:Socket 类和 ServerSocket类

5、一个 Socket 实例代表了 TCP 连接的一个客户端,而一个 ServerSocket 实例代表了 TCP 连接的一个服务器端

6、一般在 TCP Socket 编程中,客户端有多个,而服务器端只有一个,客户端 TCP 向服务器端 TCP 发送连接请求,服务器端的 ServerSocket 实例则监听来自客户端的 TCP 连接请求,并为每个请求创建新的 Socket 实例,由于服务端在调用 accept() 等待客户端的连接请求时会阻塞,直到收到客户端发送的连接请求才会继续往下执行代码,因此要为每个Socket连接开启一个线程

7、服务器端要同时处理 ServerSocket 实例和 Socket 实例,而客户端只需要使用 Socket 实例。另外每个 Socket 实例会关联一个 InputStream 和 OutputStream 对象,通过将字节写入套接字的 OutputStream 来发送数据,并通过从 InputStream 来接收数据。

8、套接字之间的连接过程分为三个步骤:1、服务器监听;2、客户端请求;3、连接确认,4)收发消息。

1)服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求

    /*** 创建绑定到特定端口的 TCP 服务端实例* ServerSocket(int port):指定绑定的端口,默认的tcp队列大小为50,默认监听本地所有的ip地址(如果有多个网卡)* ServerSocket(int port, int backlog, InetAddress bindAddr)*      port)绑定的端口*      backlog)TCP连接队列大小*      bindAddr)多网卡时指定绑定哪个 IP 地址* 如果被绑定的端口已经被其它应用绑定,如 Mysql 的 3306,Tomcat 的 8080 等,* 则此时绑定会抛出异常:java.net.BindException: Address already in use:*/ServerSocket serverSocket = new ServerSocket(8080);/*** 侦听 TCP 客户端的连接* 该方法会从全连接队列中获取一个客户端Socket请求。* 该方法是阻塞方法,如果当前没有请求的连接,则会一直阻塞,直到有客户端连接请求为止* 服务器端的 ServerSocket 实例则监听来自客户端的 TCP 连接请求,并为每个请求创建新的 Socket 实例*/Socket socket = serverSocket.accept();System.out.println("客户端连接成功:" + socket.getRemoteSocketAddress());

2)客户端请求:客户端的套接字( Socket )需要知道服务器端套接字(ServerSocket)的地址和端口号,然后向服务器端套接字提出连接请求

    /*** Socket(String host, int port):*      host)被连接的服务器 IP 地址*      port)被连接的服务器监听的端口* Socket(InetAddress address, int port)*      address)用于设置 ip 地址的对象* 此时如果 TCP 服务器未开放,或者其它原因导致连接失败,则抛出异常:* java.net.ConnectException: Connection refused: connect*/Socket socket = new Socket("127.0.0.1", 8080);System.out.println("连接成功..........");

3)连接确认:当服务器端套接字( ServerSocket )监听到或者说接收到客户端套接字( Socket) 的连接请求时,就响应客户端套接字的请求,并把服务器端套接字的描述返回给客户端,一旦客户端确认了此描述,双方就正式建立连接。

2、注意,应该使用多线程,每监听到一个,就新开一个线程来处理,使服务器端套接字一直处于监听状态,继续接收其他客户端套接字的连接请求

4)收发消息

TCP 服务器端编码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/*** Created by Administrator on 2018/10/14 0014.* TCP 服务端*/
public class TcpServer {public static void main(String[] args) {tcpAccept();}/*** Tcp 服务端介绍连接*/public static void tcpAccept() {ServerSocket serverSocket = null;try {/*** 创建绑定到特定端口的 TCP 服务端实例* ServerSocket(int port):指定绑定的端口,默认的tcp队列大小为50,默认监听本地所有的ip地址(如果有多个网卡)* ServerSocket(int port, int backlog, InetAddress bindAddr)*      port)绑定的端口*      backlog)TCP连接队列大小*      bindAddr)多网卡时指定绑定哪个 IP 地址* 如果被绑定的端口已经被其它应用绑定,如 Mysql 的 3306,Tomcat 的 8080 等,* 则此时绑定会抛出异常:java.net.BindException: Address already in use:*/serverSocket = new ServerSocket(8080);/*** 侦听 TCP 客户端的连接,TCP 是典型的 BIO 模型,即同步则塞式网络编程,必须保证循环不间断的监听客户端的连接* 对于每一个 TCP 的客户端连接都要新开线程进行数据处理* accept() 方法会从全连接队列中获取一个客户端Socket请求。* accept() 方法是阻塞方法,如果当前没有请求的连接,则会一直阻塞,直到有客户端连接请求为止* 服务器端的 ServerSocket 实例则监听来自客户端的 TCP 连接请求,并为每个请求创建新的 Socket 实例*/while (true) {System.out.println("等待客户端连接......" + Thread.currentThread().getName());final Socket socket = serverSocket.accept();/** 设置输入流读取数据的超时时间为 10 秒*//*socket.setSoTimeout(10 * 1000);*/System.out.println("客户端连接成功......" + Thread.currentThread().getName());new Thread() {@Overridepublic void run() {try {InputStream inputStream = socket.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");/** 使用 BufferedReader 逐行读取更方便*/BufferedReader bufferedReader = new BufferedReader(inputStreamReader);StringBuffer message = new StringBuffer();String readline = null;/*** TCP 连接成功之后,输入流 InputStream 读取数据的方法也会一直阻塞等待接收对方的数据* 当使用了 Socket 的 setSoTimeout(int timeout) 方法设置超时时间后,则在指定的时间内没有* 接收倒是数据时,则抛异常:java.net.SocketTimeoutException: Read timed out*/while ((readline = bufferedReader.readLine()) != null) {message.append(readline + "\n");}System.out.println(Thread.currentThread().getName() + " 收到消息:" + message.toString());bufferedReader.close();inputStreamReader.close();inputStream.close();} catch (IOException e) {e.printStackTrace();} finally {/**操作完毕,关闭 Socket 连接*/try {if (!socket.isClosed()) {socket.close();}} catch (IOException e) {e.printStackTrace();}}}}.start();}} catch (IOException e) {e.printStackTrace();} finally {/*** 如果抛出异常,则关闭 Tcp 服务器*/if (serverSocket != null && !serverSocket.isClosed()) {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

TCP 客户端端编码

import java.io.*;
import java.net.Socket;
/*** Created by Administrator on 2018/10/14 0014.* TCP 客户端*/
public class TcpClient {public static void main(String[] args) {/*** 使用三个线程模拟 3 个 TCP 客户端进行连接* 连接成功后,给服务器发送一条消息*/for (int i = 0; i < 3; i++) {new Thread() {@Overridepublic void run() {tcpSendMessage();}}.start();}}/*** Tcp 客户端连接服务器并发送消息*/public static void tcpSendMessage() {Socket socket = null;try {/*** Socket(String host, int port):*      host)被连接的服务器 IP 地址*      port)被连接的服务器监听的端口* Socket(InetAddress address, int port)*      address)用于设置 ip 地址的对象* 此时如果 TCP 服务器未开放,或者其它原因导致连接失败,则抛出异常:* java.net.ConnectException: Connection refused: connect*/socket = new Socket("127.0.0.1", 8080);System.out.println("连接成功.........." + Thread.currentThread().getName());/** 往服务端发送一条消息,指定字符编码为 UTF-8*/OutputStream outputStream = socket.getOutputStream();OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");outputStreamWriter.write("修长城的民族!,客户端=" + Thread.currentThread().getName());outputStreamWriter.flush();outputStreamWriter.close();outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();} finally {/** 操作完毕关闭 socket*/if (socket != null && !socket.isClosed()) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

运行结果,服务端如下:

等待客户端连接......main
客户端连接成功......main
等待客户端连接......main
客户端连接成功......main
等待客户端连接......main
客户端连接成功......main
等待客户端连接......main
Thread-0 收到消息:修长城的民族!,客户端=Thread-2

Thread-1 收到消息:修长城的民族!,客户端=Thread-0

Thread-2 收到消息:修长城的民族!,客户端=Thread-1

运行结果,客户端如下:

连接成功..........Thread-1
连接成功..........Thread-2
连接成功..........Thread-0

3、《传统 BIO 编程》中也有一个示例。

连接超时与读取超时

方式一:

Socket s = new Socket(String host, String port);//此时就会发起连接

当采用此方式创建 Socket 时,查看源码可知,默认的链接超时时间为 0,意味着链接永不超时,直到发生链接超时异常,最终抛出异常:java.net.SocketTimeoutException: connect timed out

实测效果是:此时如果连接不上服务端,则进程会卡死4-5秒左右,然后抛出超时异常。

方式二:

Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(serverIp, port);
socket.connect(socketAddress, timeout);//timeout为毫秒,此时会发起连接

应该使用 connect 方法来设置连接超时时间,单位毫秒

注意事项:

1、socket.setSoTimeout(3000);// 读取操作是阻塞的,这是设置读取超时时间,并不是连接超时时间

2、连接超时应该使用 connect(SocketAddress endpoint, int timeout) 方法

网络编程

1、技术日新月异,目前网络编程最为流行的当属 Netty,Java 网络编程发展历程:

JDK 1.4 以前:java.net + java.io——即平时所使用的简单的 TCP 、UDP 编程

JDK 1.4 及以后:java.nio

当下流行:JBoos 的 Netty 库、Apache 的  Mina 等

2、如下所示的《Netty 权威指南》下载地址:https://download.csdn.net/download/wangmx1993328/10717896

TCP 理论概述与 Java 编码入门相关推荐

  1. java sca_SCA java编码入门

    调出单机的Tuscany运行时 当开始考虑Tuscany SCA java运行时环境的时候,理解高层调用是什么和为什么是非常有用的.当前关于"Domain"对象有些实现,该对象用于 ...

  2. 视频编码零基础入门(1):视频编解码之理论概述

    1.前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关 ...

  3. Java极速入门系列:第一章Java概述、Java环境、IDEA开发工具

    Java极速入门-第一章Java概述.Java环境.IDEA开发工具 一.什么是Java 1.好的编程语言的特性 2.Java的特点 3.Java的运行机制 4.Java的三大体系 5.Java环境 ...

  4. Java语言入门概述

    一.Java语言入门 一)Java语言概述 1.计算机的发展,软件开发介绍 概述: 软件:即一系列按照特定的顺序组织的计算机数据和指令的集合.软件分为系统软件和应用软件. 系统软件:系统软件就是指控制 ...

  5. Java中的字符集编码入门Java中的增补字符

    转载自:http://jiangzhengjun.iteye.com/blog/512083 Java中的字符集编码入门Java中的增补字符 博客分类: 字符集编码 Java Java号称对Unico ...

  6. 视频编解码之理论概述 和即时通信

    前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关实时 ...

  7. 学Java 这样入门 28天轻松掌握

    学习Java如何才算是入门,这是很多初学者要接触的第一个知识上的瓶颈,Java如何学习.学习到那一步才能够成功继续往下走. 万事开头难编程入门更是如此,编程入门我们了解语言的体系,锻炼自己的编程思维方 ...

  8. JAVA编程思想.姊妹篇.JAVA编程讲义.第1章 Java开发入门

    1.1 Java概述 1.1.1 Java的由来与发展 Java是一种高级计算机语言,它是由Sun公司(2009年4月20日被Oracle公司收购,2010年完成合并)于1995年5月推出的一种用来编 ...

  9. java从入门到精通 ppt_《Java从入门到精通》第4版全书完整PPT课件

    [实例简介] <Java从入门到精通>第4版全书完整PPT课件 [实例截图] [核心代码] e3a1ab08-ca73-47e5-9a3a-bec0b60c991a └── <Jav ...

  10. Docker基本理论概述

    < Docker基本理论概述 > 关于Docker 1.为什么要使用 Docker ? 项目从开发到上线,从操作系统,到运行环境,再到应用的详细配置.作为开发工程师与运维工程师之间的协作, ...

最新文章

  1. Word中的字体大小
  2. 马斯克发推警告:高级AI将操纵社交媒体,或引发第三次世界大战
  3. m.2接口和nvme区别_M.2硬盘的分类和区别
  4. python数字倒序
  5. Win7电脑快速获取超级管理员权限的方法
  6. 我的docker随笔35:jenkins服务部署
  7. 堆排序算法思路以及Java实现
  8. 百度地图 根据经纬度获取 地址
  9. r语言员工离职_基于随机森林的优秀员工离职因素实证分析及预测
  10. FidMTF: An MTF Estimator (FidMTF:一种MTF估计方法)
  11. 笔记本触摸屏使用技巧
  12. 2022数据安全法律法规标准关注文件整理
  13. JS ListBox动态加载数据
  14. 无线调试——免除数据线的干扰
  15. TensorFlow1.x最佳实践:Dataset API+Keras Model+TF Train
  16. 电脑影响,重装系统对电脑有什么影响,教您经常重装系统对电脑有什么影响
  17. maven 依赖包查询
  18. RTX基于32位Windows实时操作系统
  19. unity3d求一个向量的垂直方向
  20. 【力扣周赛】第343场周赛

热门文章

  1. 关于以主机命名的网站集
  2. 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果及其他。
  3. mysql分库分表 mycat_你们要的MyCat实现MySQL分库分表来了
  4. 利用sklearn对红酒数据集分类
  5. smale学习之数学表达式(day3)
  6. python10进制2进制转换
  7. 决策树的sklearn实现及其GraphViz可视化
  8. Firefox 2015 最受国人欢迎的十大扩展
  9. caffe的python接口学习(2):生成solver文件
  10. 周志华机器学习西瓜书速记第一章绪论