【Java TCP/IP Socket】深入剖析socket——TCP套接字的生命周期

建立TCP连接

新的Socket实例创建后,就立即能用于发送和接收数据。也就是说,当Socket实例返回时,它已经连接到了一个远程终端,并通过协议的底层实现完成了TCP消息或握手信息的交换。

客户端连接的建立

Socket构造函数的调用与客户端连接建立时所关联的协议事件之间的关系下图所示:

当客户端以服务器端的互联网地址W.X.Y.Z和端口号Q作为参数,调用Socket的构造函数时,底层实现将创建一个套接字实例,该实例的初始状态是关闭的。TCP开放握手也称为3次握手,这通常包括3条消息:一条从客户端到服务端的连接请求,一条从服务端到客户端的确认消息,以及另一条从客户端到服务端的确认消息。对客户端而言,一旦它收到了服务端发来的确认消息,就立即认为连接已经建立。通常这个过程发生的很快,但连接请求消息或服务端的回复消息都有可能在传输过程中丢失,因此TCP协议实现将以递增的时间间隔重复发送几次握手消息。如果TCP客户端在一段时间后还没有收到服务端的回复消息,则发生超时并放弃连接。如果服务端并没有接收连接,则服务端的TCP将发送一条拒绝消息而不是确认消息。

服务端连接的建立

当客户端的事件序列则有所不同。服务端首先创建一个ServerSocket实例,并将其与已知端口相关联(在此为Q),套接字实现为新的ServerSocket实例创建一个底层数据结构,并就Q赋给本地端口,并将特定的通配符(*)赋给本地IP地址(服务器可能有多个IP地址,不过通常不会指定该参数),如下图所示:

现在服务端可以调用ServerSocket的accept()方法,来将阻塞等待客户端连接请求的到来。当客户端的连接请求到来时,将为连接创建一个新的套接字数据结构。该套接字的地址根据到来的分组报文设置:分组报文的目标互联网地址和端口号成为该套接字的本地互联网地址和端口号;而分组报文的源地址和端口号则成为改套接字的远程互联网地址和端口号。注意,新套接字的本地端口号总是与ServerSocket的端口号一致。除了要创建一个新的底层套接字数据结构外,服务端的TCP实现还要向客户端发送一个TCP握手确认消息。如下图所示:

但是,对于服务端来说,在接收到客户端发来的第3条消息之前,服务端TCP并不会认为握手消息已经完成。一旦收到客户端发来的第3条消息,则表示连接已建立,此时一个新的数据结构将从服务端所关联的列表中移除,并为创建一个Socket实例,作为accept()方法的返回值。如下图所示:

 这里有非常重要的一点需要注意,在ServerSocket关联的列表中的每个数据结构,都代表了一个与另一端的客户端已经完成建立的TCP连接。实际上,客户只要收到了开放握手的第2条消息,就可以立即发送数据——这可能比服务端调用accept()方法为其获取一个Socket实例要早很长时间。

 

关闭TCP连接

TCP协议有一个优雅的关闭机制,以保证应用程序在关闭时不必担心正在传输的数据会丢失,这个机制还可以设计为允许两个方向的数据传输相互独立地终止。关闭机制的工作流程是:应用程序通过调用连接套接字的close()方法或shutdownOutput()方法表明数据已经发送完毕。底层TCP实现首先将留在SendQ队列中的数据传输出去(这还要依赖于另一端的RecvQ队列的剩余空间),然后向另一端发送一个关闭TCP连接的握手消息。该关闭握手消息可以看做流结束的标志:它告诉接收端TCP不会再有新的数据传入RecvQ队列了。注意:关闭握手消息本身并没有传递给接收端应用程序,而是通过read()方法返回-1来指示其在字节流中的位置。而正在关闭的TCP将等待其关闭握手消息的确认消息,该确认消息表明在连接上传输的所有数据已经安全地传输到了RecvQ中。只要收到了确认消息,该连接变成了“半关闭”状态。直到连接的另一个方向上收到了对称的握手消息后,连接才完全关闭——也就是说,连接的两端都表明它们没有数据发送了。

TCP连接的关闭事件序列可能以两种方式发生:一种方式是先由一个应用程序调用close()方法或shutdownOutput方法,并在另一端调用close()方法之前完成其关闭握手消息;另一种方式是两端同时调用close()方法,他们的关闭握手消息在网络上交叉传输。下图展示了以第一种方式关闭连接时,发起关闭的一端底层实现中的事件序列:

注意,如果连接处于半关闭状态时,远程终端已经离开,那么本地底层数据结构则无限期地保持在该状态。当另一端的关闭握手消息到达后,则发回一条确认消息并将状态改为“Time—Wait”。虽然应用程序中相应的Socket实例可能早已消失,与之关联的底层数据结构还将在底层实现中继续存留几分钟。

对于没有首先发起关闭的一端,关闭握手消息达到后,它立即发回一个确认消息,并将连接状态改为“Close—Wait”。此时,只需要等待应用程序调用Socket的close()方法。调用该方法后,将发起最终的关闭消息 ,并释放底层套接字数据结构。 下图展示了没有首先发起关闭的一端底层实现中的事件序列:

     注意这样一个事实:close()方法和shutdownOutput()方法都没有等待关闭握手的完成,而是调用后立即返回,这样,当应用程序调用close()方法或shutdownOutput()方法并成功关闭连接时,有可能还有数据留在SendQ队列中。如果连接的任何一端在数据传输到RecvQ队列之前崩溃,数据将丢失,而发送端应用程序却不会知道。

     最好的解决方案是设计一种应用程序协议,以使首先调用close()方法的一方在接收到了应用程序的数据已接收保证后,才真正执行关闭操作。例如,在http://blog.csdn.net/ns_code/article/details/14642873这篇博客的分析示例中,客户端程序确认其接收到的字节数与其发送的字节数相等后,它就能够知道此时在连接的两个方向上都没有数据在传输,因此可以安全地关闭连接。

 

关闭TCP连接的最后微妙之处在于对Time—Wait状态的需要。TCP规范要求在终止连接时,两端的关闭握手都完成后,至少要有一个套接字在Time—Wait状态保持一段时间。这个要求的提出是由于消息在网络中传输时可能延迟。如果在连接两端都完成了关闭握手后,它们都移除了其底层数据结构,而此时在同样一对套接字地址之间又建立了新的连接,那么前一个连接在网络上传输时延迟的消息就可能在新建立的连接后到达。由于包含了相同的源地址和目的地址,旧消息就会被错误地认为是属于新连接的,其包含的数据就可能被错误地分配到应用程序中。虽然这种情况很少发生,TCP还是使用了包括Time—Write状态在内的多种机制对其进行防范。

Time—Wait状态最重要的作用是:只要底层套接字数据结构还存在,就不允许在相同的本地端口上关联其他套接字,尤其试图使用该端口创建新的Socket实例时,将抛出IOException异常。

转自:http://blog.csdn.net/ns_code/article/details/16113083

时间: 2024-11-03 19:55:55

【Java TCP/IP Socket】深入剖析socket——TCP套接字的生命周期的相关文章

深入浅出--iOS的TCP/IP协议族剖析&&Socket

深入浅出--iOS的TCP/IP协议族剖析&&Socket 简介 该篇文章主要回顾--TCP/IP协议族中的TCP/UDP.HTTP:还有Socket.(--该文很干,酝酿了许久!你能耐心看完吗?) 我在这个文章中,列举了常见的TCP/IP族中的协议,今天主角是--传输层协议. 传输层(Transport Layer)是OSI(七层模型)中最重要.最关键的一层,它负责总体的数据传输和数据控制的一层,传输层提供端到端(应用会在网卡注册一个端口号)的交换数据的机制,检查分组编号与次序.传输层对

iOS的TCP/IP协议族剖析&&Socket

原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 简介 该篇文章主要回顾--TCP/IP协议族中的TCP/UDP.HTTP:还有Socket.(--该文很干,酝酿了许久!你能耐心看完吗?O_o) 我在这个文章中,列举了常见的TCP/IP族中的协议,今天主角是--传输层协议. 传输层(Transport Layer)是OSI(七层模型)中最重要.最关键的一层,它负责总体的数据传输和数据控制的一层,传输层提供端到端(应用会在网卡注

iOS 的 TCP/IP 协议族剖析 && Socket

简介 该篇文章主要回顾–TCP/IP协议族中的TCP/UDP.HTTP:还有Socket.(--该文很干,酝酿了许久!你能耐心看完吗?O_o) 我在这个文章中,列举了常见的TCP/IP族中的协议,今天主角是--传输层协议. 传输层(Transport Layer)是OSI(七层模型)中最重要.最关键的一层,它负责总体的数据传输和数据控制的一层,传输层提供端到端(应用会在网卡注册一个端口号)的交换数据的机制,检查分组编号与次序.传输层对其上三层如会话层等,提供可靠的传输服务,对网络层提供可靠的目的

【TCP/IP网络编程】:02套接字类型与协议设置

本篇文章主要介绍创建套接字函数相关的3个输入参数的含义,它们最终确定了套接字通信所采用的协议.同时,也简单对比了TCP和UDP传输方式的区别. 什么是协议?协议是对话中使用的通信规则,而在计算机领域则可解释为“计算机间对话的通信规则”.简言之,协议就是为了完成数据交换而约定的规则. //创建套接字 #include <sys/socket.h> int socket(int domain, int type, int protocol); -> 成功时返回文件描述符,失败时返回-1 do

java tcp ip网络编程(二) 套接字的基本使用

##基本套接字的使用 linux系统把网络io抽象成socket,对网络的编程就是对socket的编程. java把套接字抽象成类似的类 InetAddress SocketAddress 识别java应用程序如何识别网络主机 客户端Socket类 ServerSocket类 UDP类 DatagramSocket 获取用户的网卡和对应的ip信息 通过host获取对应的网络地址```Enumeration<NetworkInterface> networkInterfaceEnumeratio

赵雅智_java网络编程(4)TCP/IP、Http和Socket的区别

通过java网络编程(1)网络体系结构及通信协议我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层, 三者从本质上来说没有可比性 TPC/IP协议是传输层协议,主要解决数据如何在网络中传输, 而HTTP是应用层协议,主要解决如何包装数据. socket是对TCP/IP协议的封装和应用(程序员层面上). 三者关系 总的来说 传输层的TCP是基于网络层的IP协议的 应用层的HTTP协议又是基于传输层的TCP协议的 Socket本身不算是协议,它只是提供了一个针对TCP或者

TCP/IP、Http、Socket的区别

网络由下往上分为 物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层, 三者从本质上来说没有可比性, socket则是对TCP/IP协议的封装和应用(程序员层面上). 也可以说,TPC/IP协议是传输层协议,主要解决数据如何在网络中传输, 而HTTP是应用层协议,主要解决如何包装数据. 关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍: “我们在传输数据时,可以只使用(传输

TCP/IP、Http、Socket、XMPP-从入门到深入

TCP/IP.Http.Socket.XMPP-从入门到深入 终极iOS程序猿 2016-12-29 18:27 为了便于大家理解和记忆,我们先对这几个概念进行的介绍,然后分析他们的不同,再进行详细的分析. 一.TCP/IP简介 IP协议是网络层,TCP协议是传输层,HTTP协议是应用层,socket是对TCP/IP协议的代码封装和应用. TPC/IP 主要解决数据如何在网络中传输,HTTP主要解决如何包装数据. TCP/IP协议用来传输数据,应用层协议 使传输的数据有意义,应用层协议有很多,比

TCP/IP,Http,Socket,XMPP的区别

大学学习网络基础的时候老师讲过,网络由下往上分为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层.通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层,三者从本质上来说没有可比性,socket则是对TCP/IP协议的封装和应用(程序员层面上).也可以说,TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据.关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍: “我们在传输数据时