转载请注明出处:http://blog.csdn.net/ns_code/article/details/16113083


建立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异常。

《Java TCP/IP Socket 编程 》读书笔记之十一:深入剖析socket——TCP套接字的生命周期的更多相关文章

  1. TCP/IP网络编程 读书笔记1

    本篇主干内容是TCP/IP网络编程1-9章学习笔记 1. linux文件描述符 描述符从3开始以由小到大的顺序编号,0,1,2,分配给标准I/O用作标准输入.标准输出和标准错误. 2. 协议族与套接字 ...

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

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

  3. 《TCP/IP图解》读书笔记

    看这本书的目的: 了解计算机之间是怎么通信的 熟悉TCP/IP协议 后面就这两个目的进行展开,要达到这两个目的,读这本书,学到了哪些知识. 一.计算机之间是怎么通信的 先来了解下面几个概念,中继器,二 ...

  4. TCP/IP知识总结(TCP/IP协议族读书笔记四)

    参考:http://blog.chinaunix.net/uid-26275986-id-4109679.html 继续!TCP的流量控制和拥塞控制. TCP相对UDP可靠的地方在于它的拥塞控制.流量 ...

  5. TCP/IP知识总结(TCP/IP协议族读书笔记三)

    接下来,总结传输层的两大协议UDP和TCP. 一.UDP(用户数据报协议) 讲UDP之间,先了解两个概念:有连接和无连接. 有连接:通信之前,通信双方必须建立一条通道: 无连接:不需要建立通道,发送方 ...

  6. TCP/IP知识总结(TCP/IP协议族读书笔记二)

    接下来,总结一下网络层的协议,IP,ARP,RARP,ICMP,IGMP.当我们在网络传输的过程中,把分组交付到主机或路由器需要两级地址:物理地址和逻辑地址.而且我们需要能够把物理地址映射成为相应的逻 ...

  7. TCP/IP知识总结(TCP/IP协议族读书笔记一)

    一.简述TCP/IP协议 Transmission Control Protocol/Internet Protocol的简写,即传输控制协议/互联网互联协议,又名网络通信协议.是Internet最基 ...

  8. TCP/IP详解 读书笔记:TCP:传输控制协议

    TCP的服务 TCP为应用层提供一种面向连接的.可靠的字节流服务. 一个TCP连接中,仅有两方进行彼此通信,所以广播和多播不能用于TCP. TCP通过以下方式提供可靠性: 应用数据被切割为TCP认为最 ...

  9. TCP/IP详解 读书笔记(一):概述

    分层 网络协议通常分不同层次进行开发,每一层负责不同的职责,一个协议簇指的是一组不同层次上的多个协议的组合. TCP/IP通常被认为是一个四层协议系统: 链路层:主要是处理与电缆或其他传输媒介的物理接 ...

随机推荐

  1. 为SQL Server 增加链接到SQL Server 的链接服务器

    整体的分析一下好有一个思路.我们的目的是完成一个到远程服务器的链接. 第一:我们要知道这台服务器在哪(也就是要知道它的IP地址,如果是在同一个网络中知道它的计算机名也是可以的.因为一台服务器上可以安装 ...

  2. 测试linux和window下 jdk最大能使用多大内存

    在命令行下用 java -XmxXXXXM -version 命令来进行测试,然后逐渐的增大XXXX的值,如果执行正常就表示指定的内存大小可用,否则会打印错误信息. 发现在linux先 最多用java ...

  3. ViewPager不能高度自适应?height=wrap_content 无效解决办法

    ViewPager用的很多,主要用啦展示广告条.可是高度却不能自适应内容,总是会占满全屏,即使设置android:height="wrap_content"也是没有用的.. 解决办 ...

  4. mysql 批量删除分区

    alter table titles drop partition p01; use zabbix; mysql> source drop_par.sql [oracle@oadb mysql] ...

  5. CCNP路由实验(3) -- 路由控制

    1.用distribute-list过滤路由在不同协议里的用法 在RIP里 在EIGRP里 在OSPF里 只接收奇数路由 只接收偶数路由 只接收被4整除的路由2.offset-list在不同协议里的用 ...

  6. DLL编写教程(绝对经典之作)

    DLL编写教程 半年不能上网,最近网络终于通了,终于可以更新博客了,写点什么呢?决定最近写一个编程技术系列,其内容是一些通用的编程技术.例如DLL,COM,Socket,多线程等等.这些技术的特点就是 ...

  7. 迭代器(iterators)

    1.迭代器的概念 迭代器是一种抽象的设计概念.在设计模式中,迭代器模式定义为:提供一种方法,使之能够依序访问某个容器中所含的各个元素,而又无需暴露该容器的内部组织结构. 迭代器可以看做一种行为类似指针 ...

  8. QT与JavaScript互调 - 虹的日志 - 网易博客

    QT与JavaScript互调 - 虹的日志 - 网易博客 QT与JavaScript互调   2012-05-29 21:43:14|  分类: 技术 |  标签:qt  javascript  w ...

  9. Javascript高级程序设计学习笔记一

    看完w3school的javascript的概念,有点基础,开始红皮书的路程,今晚总结前二章的心得. 第一章:javascript简介 重点是javascript的实现是由 ECMAScript(核心 ...

  10. NGUI Button 3中点击事件的触发

    NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定在按钮上,点击按钮触发的方法名必须为OnClick,当 ...