精华内容
下载资源
问答
  • TCP连接

    万次阅读 2018-05-24 15:48:55
    TCP连接的端点又叫套接字(socket),根据TCP协议的规定,端口号拼接到IP地址即构成了套接字,即套接字 socket = (IP地址:端口号)这样一来,TCP连接可以以下式子表示TCP连接 ::= {socket1, socket2} = {(IP1:...

    简述

    TCP是面向连接的协议,TCP把连接作为最基本的抽象。每一条TCP连接唯一地被通信两端的两个端点所确定。那么,TCP连接的端点是什么呢?TCP连接的端点又叫套接字(socket),根据TCP协议的规定,端口号拼接到IP地址即构成了套接字,即

    套接字 socket = (IP地址:端口号)

    这样一来,TCP连接可以以下式子表示

    TCP连接 ::= {socket1, socket2} = {(IP1: port1),(IP2: port2)}

    在面向连接通信中,连接的建立和释放是必不可少的过程。TCP连接的建立采用客户服务器方式,主动发起连接建立的应用进程叫做客户,而被动等待连接的应用进程叫做服务器。 
    本文主要讲述TCP是如何管理连接的建立和连接的释放的。

    TCP的连接建立

    三次握手建立TCP连接
    图1:三次握手建立TCP连接

    图1画出了TCP连接建立的过程。假定图中左端是客户A,右端是服务器B,一开始时,两端都处于CLOSED(关闭)状态。图中的方框分别是端点所处的状态。 
    1)服务器进程准备好接受外来的连接,这通常是通过调用socket,bind,listen这三个函数来完成,我们称之为被动打开(passive open)。然后服务器进程就处于LISTEN状态,等待客户的连接请求,如有,则作出响应。 
    2)客户通过调用connect发起主动打开(active open),向服务器发出连接请求报文段,请求中的首部的同步位SYN = 1,同时选择一个初始序号seq = x。TCP规定,SYN报文段不能携带数据,则要消耗一个序号。 
    这时,TCP客户进入SYN-SEND(同步已发送)状态。

    TCP规定,首部中序号字段值是本报文段所发送数据的第一个字节的序号。

    3)服务器收到客户端连接请求后,必须确认(ACK)客户的SYN报文段。在确认报文段中,把SYN和ACK位都置为1,确认号为ack = x + 1,同时也为自己选择一个初始序号seq = y。请注意,这个报文段也不能携带数据,但同样要消耗掉一个序号。 
    这时,TCP服务器进入SYN-RCVD(同步收到)状态。

    TCP规定,若确认号 = N,则表明:到序号 N - 1为止的所有数据都已正确收到。

    4)客户在收到服务器的确认后,还要向服务器进程给出确认。确认报文段的ACK置1,确认号ack = y + 1,而自己的序号seq = x + 1。TCP规定,这个报文段可以携带数据,也可以不携带数据,如果不携带数据,下一个数据报文段的序号仍是seq = x + 1。 
    这时,TCP连接已经建立,客户进入ESTABLISHED(已建立连接)状态。 
    5)服务器收到客户的确认后,也进入ESTABLISHED状态。 
    在上述的建立连接的过程中,前后发送了三个报文段,因此TCP建立连接的过程也称之为三次握手(three-way handshake)。

    为什么需要三次握手

    为什么客户在收到服务器的确认后,还要向服务器发送一次确认呢?这主要是为了防止已失效的连接请求报文段突然又传送到了服务器,因而发生错误。 
    考虑一种情况,客户发出连接请求后,但因连接请求报文丢失而未收到确认。于是客户再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。客户共发送了两个连接请求报文段,其中第一个丢失,第二个到达了服务器。没有“已失效的连接请求报文段”。 
    现假定一种异常情况。即客户发出的第一个连接请求报文段并没有丢失,而是在某些网络结点长时间滞留了,以致延误到连接释放以后的某个时间才到达服务器。本来这是一个早已失效的报文段,但服务器收到此失效的连接请求后,就误认为是客户又一次发出一次新的连接请求。于是就向客户发出确认报文段,同意建立连接。假定不采用三次握手,那么只要服务器发出确认,新的连接就建立了。 
    由于现在客户端并没有发出建立连接的请求,因此不会理睬服务器的确认,也不会向服务器发送数据。但服务器却以为新的连接已经建立了,并一直等待客户发送数据。服务器的许多资源就这样白浪费了。 
    采用三次握手的办法可以防止上述现象的发生。例如刚才的情况下,客户不会向服务器的确认发出确认,由于服务器收不到确认,就知道客户并没有要求建立连接。

    TCP的连接释放

    TCP建立一个连接需要三个报文段,释放一个连接却需要四个报文段。 
    TCP释放连接的过程
    图2:TCP释放连接的过程

    数据传输结束后,通信的双方可以释放连接。数据传输结束后的客户A和服务器B都处于ESTABLISHED状态,然后进入释放连接的过程。 
    1)A的应用进程先发出释放连接报文段,并停止发送数据,主动关闭TCP连接。A把连接释放报文段首部FIN置1,其序号为seq = u。这时A进入FIN-WAIT-1(终止等待1)状态。 
    2)B收到连接释放报文段后即发出确认确认号为ack = u + 1,而自己的序号为seq = v。然后B就进入CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时应通知高层应用进程,因而从A到B这个方向的连接就释放了,这时的TCP连接处于半关闭状态,即A已经没有数据要发送了,但B若发送数据,A仍接收。 
    3)A收到来自B的确认后,就进入FIN-WAIT-2(终止等待2)状态,等待B发出的连接释放报文段。 
    4)若B已经没有要向A发送的数据,其应用进程就通知TCP释放 连接。这时B发出的连接释放报文段FIN = 1,还必须重复上次已发送过的确认号ack = u + 1。假定B的序号为w(在半关闭期间B可能又发送了一些数据)。这时B就进入了LAST-ACK(最后确认)状态,等待A的确认。 
    5)A收到了的连接释放报文段后,必须对此发出确认。其确认号为ack = w + 1,而自己的序号为seq = u + 1。然后进入到TIME-WAIT(时间等待)状态。请注意,现在TCP连接还没有释放掉。必须经过时间等待计时器(TIME-WAIT timer)设置的时间 2MSL后,A才进入到CLOSED状态。时间MSL叫做最长报文段寿命(Maximum Segment Lifetime)。 
    6)B只要收到A发出的确认,就进入CLOSED状态。我们注意到,B结束TCP连接的时间要比A早一些。 
    由于释放TCP连接的过程需要发送四个报文段,因此释放连接的过程也称之为四次握手。

    TIME_WAIT状态

    上述释放连接的过程中,A在TIME-WAIT状态必须等待2MSL,才进入CLOSED状态,上面也提到,这个MSL是报文段的最长寿命。那么MSL的真实含义是什么呢? 
    MSL是任何IP数据报能够在网络中存活的最长时间。我们知道这个时间是有限的,因为每个数据报含有一个称为跳限(hop limit)的8位字段,它的最大值是255,即最大为255跳。尽管这是一个跳数限制而不是真正的时间限制,我们仍然假设:具有最大跳限的数据报在网络中存在的时间不可能超过MSL秒。 
    任何TCP实现都必须为MSL选择一个值。RFC 1122的建议值为2分钟,对于现在的网络,MSL = 2分钟可能太长了,故一些实现采用30秒的值,这意味着,TIME-WAIT状态的持续时间在1分钟到4分钟之间。 
    为什么客户在TIME-WAIT状态必须2MSL的时间呢?这有两个理由: 
    1)可靠地实现TCP全双工连接的终止 
    客户A最后一个ACK报文段可能丢失,这样服务器B处于LAST-ACK状态而收不到确认。接下来B会超时重传FIN + ACK报文段,而A就能在2MSL时间内收到这个重传的FIN + ACK报文段,并再重传一次确认,并重新启动2MSL计时器。最后,A和B都正常进入CLOSED状态。 
    如果A在发送完最后一个ACK报文段后立即释放连接,那么就无法收到B重传的FIN + ACK报文段,因而也不会再发送一次确认报文段,这样B就无法按照正常步骤进入CLOSED状态。 
    2)防止“已失效的连接请求报文段”出现在本连接中 
    客户A在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都会网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

    后记

    有这样一道面试题,对于应用程序来说,什么情况下会出现大量 TIME_WAIT 的状态? 
    TIME_WAIT 出现的原因可以参考上面的详细解析,从上面的描述我们也可以知道,TIME_WAIT 的出现是一般是客户主动关闭 TCP 连接而出现的,即出现在客户端机器,服务端机器一般不会出现 TIME_WAIT 状态。 
    那么,在什么情况下,客户端机器会大量出现关闭 TCP 连接呢? 
    记得在网易的时候,我曾经为处理用户连接实时语音服务的日志开发过一个日志补全进程 audiolog。 
    用户每天累积的实时语音日志达1千多万条,audiolog 进程在每天的固定时间(01:30)扫描语音日志,发现某些日志如果存在字段缺失的情况,audiolog 会通过发送 HTTP 请求查询并补全字段信息,audiolog会在短时间内扫描完所有的日志并运行完毕。我们知道 HTTP 是基于 TCP 的,这就导致短时间内 audiolog 断开大量的 TCP 连接,导致大量 TIME_WAIT 状态的出现。


    图3:audiolog 机器出现 TIME_WAIT 状态统计

    由图3可以看到,audiolog 所在的机器,在01:30这个时间点,出现了大量的 TIME_WAIT 状态,这个时间点正是 audiolog 进程运行的时间点,这跟上述分析出现大量 TIME_WAIT 状态的原因是一致的。

    上述的情况,都是在客户端出现 TIME_WAIT 的情况。另外,如果服务端主动关闭客户端非法请求或者处理长时间不跳跃连接,也会在服务端机器出现 TIME_WAIT 的状态。

    展开全文
  • TCP连接的状态详解以及故障排查

    万次阅读 多人点赞 2014-08-20 07:06:38
    我们通过了解TCP各个状态,可以排除和定位网络或系统故障时大有帮助。(总结网络上的内容) 1、TCP状态 了解TCP之前,先了解几个命令: ...3)、 sar -n SOCK 查看tcp创建的连接数 4)、tcpdump -iany...

    我们通过了解TCP各个状态,可以排除定位网络或系统故障时大有帮助。

     

    一、TCP网络常用命令


    了解TCP之前,先了解几个命令:

    linux查看tcp的状态命令:
    1)、netstat -nat  查看TCP各个状态的数量
    2)、lsof  -i:port  可以检测到打开套接字的状况
    3)、  sar -n SOCK 查看tcp创建的连接数
    4)、tcpdump -iany tcp port 9000 对tcp端口为9000的进行抓包
    5)、tcpdump   dst  port 9000 -w dump9000.pcap  对tcp目标端口为9000的进行抓包保存pcap文件wireshark分析。
    6)、tcpdump tcp port 9000  -n -X -s 0 -w tcp.cap 对tcp/http目标端口为9000的进行抓包保存pcap文件wireshark分析。

    网络测试常用命令; 

    1)ping:检测网络连接的正常与否,主要是测试延时、抖动、丢包率。

         但是很多服务器为了防止攻击,一般会关闭对ping的响应。所以ping一般作为测试连通性使用。ping命令后,会接收到对方发送的回馈信息,其中记录着对方的IP地址和TTL。TTL是该字段指定IP包被路由器丢弃之前允许通过的最大网段数量。TTL是IPv4包头的一个8 bit字段。例如IP包在服务器中发送前设置的TTL是64,你使用ping命令后,得到服务器反馈的信息,其中的TTL为56,说明途中一共经过了8道路由器的转发,每经过一个路由,TTL减1。

    2)traceroute:raceroute 跟踪数据包到达网络主机所经过的路由工具

       traceroute hostname

    3)pathping:是一个路由跟踪工具,它将 ping 和 tracert 命令的功能与这两个工具所不提供的其他信息结合起来,综合了二者的功能

       pathping www.baidu.com

    4)mtr:以结合ping nslookup tracert 来判断网络的相关特性

    5) nslookup:用于解析域名,一般用来检测本机的DNS设置是否配置正确。

     

    二、TCP建立连接三次握手相关状态


        TCP是一个面向连接的协议,所以在连接双方发送数据之前,都需要首先建立一条连接。

    1、Client连接Server三次握手过程:

         当Client端调用socket函数调用时,相当于Client端产生了一个处于Closed状态的套接字。
          ( 1)  第一次握手SYN:Client端又调用connect函数调用,系统为Client随机分配一个端口,连同传入connect中的参数(Server的IP端口),这就形成了一个连接四元组,客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。connect调用让Client端的socket处于SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

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

          ( 3)  第三次握手ACK:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户器和客务器进入ESTABLISHED状态,完成三次握手。连接已经可以进行读写操作。

    一个完整的三次握手也就是: 请求---应答---再次确认。

    TCP协议通过三个报文段完成连接的建立,这个过程称为三次握手(three-way handshake),过程如下图所示。

    Server对应的函数接口:
         当Server端调用socket函数调用时,相当于Server端产生了一个处于Closed状态的监听套接字
          Server端调用bind操作,将监听套接字与指定的地址和端口关联,然后又调用listen函数,系统会为其分配未完成队列和完成队列,此时的监听套接字可以接受Client的连接,监听套接字状态处于LISTEN状态。
         当Server端调用accept操作时,会从完成队列中取出一个已经完成的client连接,同时在server这段会产生一个会话套接字,用于和client端套接字的通信,这个会话套接字的状态是ESTABLISH。

            从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

    我们可以通过wireshark抓包,可以清晰看到查看具体的流程:

    第一次握手:syn的seq= 0
    第二次握手:服务器收到syn包,必须确认客户的SYN(ACK=j+1=1)=,同时自己也发送一个SYN包(syn=0)

    第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1)

    2、建立连接的具体状态:

        1)、LISTENING:侦听来自远方的TCP端口的连接请求.

         首先服务端需要打开一个socket进行监听,状态为LISTEN。

        有提供某种服务才会处于LISTENING状态,TCP状态变化就是某个端口的状态变化,提供一个服务就打开一个端口,例如:提供www服务默认开的是80端口,提供ftp服务默认的端口为21,当提供的服务没有被连接时就处于LISTENING状态。FTP服务启动后首先处于侦听(LISTENING)状态。处于侦听LISTENING状态时,该端口是开放的,等待连接,但还没有被连接。就像你房子的门已经敞开的,但还没有人进来。
        看LISTENING状态最主要的是看本机开了哪些端口,这些端口都是哪个程序开的,关闭不必要的端口是保证安全的一个非常重要的方面,服务端口都对应一个服务(应用程序),停止该服务就关闭了该端口,例如要关闭21端口只要停止IIS服务中的FTP服务即可。关于这方面的知识请参阅其它文章。
        如果你不幸中了服务端口的木马,木马也开个端口处于LISTENING状态。

         2)、SYN-SENT:客户端SYN_SENT状态

             再发送连接请求后等待匹配的连接请求:客户端通过应用程序调用connect进行active open.于是客户端tcp发送一个SYN以请求建立一个连接.之后状态置为SYN_SENT. /*The socket is actively attempting to establish a connection. 在发送连接请求后等待匹配的连接请求 */
         当请求连接时客户端首先要发送同步信号给要访问的机器,此时状态为SYN_SENT,如果连接成功了就变为ESTABLISHED,正常情况下SYN_SENT状态非常短暂。例如要访问网站http://www.baidu.com,如果是正常连接的话,用TCPView观察IEXPLORE.EXE(IE)建立的连接会发现很快从SYN_SENT变为ESTABLISHED,表示连接成功。SYN_SENT状态快的也许看不到。
         如果发现有很多SYN_SENT出现,那一般有这么几种情况,一是你要访问的网站不存在或线路不好,二是用扫描软件扫描一个网段的机器,也会出出现很多SYN_SENT,另外就是可能中了病毒了,例如中了"冲击波",病毒发作时会扫描其它机器,这样会有很多SYN_SENT出现。


        3)、SYN-RECEIVED:服务器端握手状态SYN_RCVD

           再收到和发送一个连接请求后等待对方对连接请求的确认

           当服务器收到客户端发送的同步信号时,将标志位ACK和SYN置1发送给客户端,此时服务器端处于SYN_RCVD状态,如果连接成功了就变为ESTABLISHED,正常情况下SYN_RCVD状态非常短暂。
       如果发现有很多SYN_RCVD状态,那你的机器有可能被SYN Flood的DoS(拒绝服务攻击)攻击了

         SYN Flood的攻击原理是:

          在进行三次握手时,攻击软件向被攻击的服务器发送SYN连接请求(握手的第一步),但是这个地址是伪造的,如攻击软件随机伪造了51.133.163.104、65.158.99.152等等地址。服务器在收到连接请求时将标志位ACK和SYN置1发送给客户端(握手的第二步),但是这些客户端的IP地址都是伪造的,服务器根本找不到客户机,也就是说握手的第三步不可能完成。

           这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒-2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源----数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。此时从正常客户的角度看来,服务器失去响应,这种情况我们称做:服务器端受到了SYN Flood攻击(SYN洪水攻击



       4)ESTABLISHED:代表一个打开的连接。

        ESTABLISHED状态是表示两台机器正在传输数据,观察这个状态最主要的就是看哪个程序正在处于ESTABLISHED状态。

        服务器出现很多ESTABLISHED状态: netstat -nat |grep 9502或者使用lsof  -i:9502可以检测到。

        当客户端未主动close的时候就断开连接:即客户端发送的FIN丢失或未发送:
        这时候若客户端断开的时候发送了FIN包,则服务端将会处于CLOSE_WAIT状态;
        这时候若客户端断开的时候未发送FIN包,则服务端处还是显示ESTABLISHED状态;
        结果客户端重新连接服务器。
        而新连接上来的客户端(也就是刚才断掉的重新连上来了)在服务端肯定是ESTABLISHED; 如果客户端重复的上演这种情况,那么服务端将会出现大量的假的ESTABLISHED连接和CLOSE_WAIT连接。
        最终结果就是新的其他客户端无法连接上来,但是利用netstat还是能看到一条连接已经建立,并显示ESTABLISHED,但始终无法进入程序代码。

     

    三、 TCP关闭四次握手的相关状态


       由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

    1、四次握手关闭连接的过程

               建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由TCP的半关闭(half-close)造成的,如图:

         

     

    调用过程和对应函数接口:

    • 1)  客户端发送一个FIN: 用来关闭客户A到服务器B的数据传送,当client想要关闭它与server之间的连接。client(某个应用进程)首先调用close主动关闭连接,这时TCP发送一个FIN M;client端处于FIN_WAIT1状态。

    • 2) 服务器确认客户端FIN: 当server端接收到FIN M之后,执行被动关闭。对这个FIN进行确认,返回给client ACK。确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。当server端返回给client ACK后,client处于FIN_WAIT2状态,server处于CLOSE_WAIT状态。它的接收也作为文件结束符传递给应用进程,因为FIN的接收     意味着应用进程在相应的连接上再也接收不到额外数据;

    • 3)  服务器B发送一个FIN关闭与客户端A的连接: 一段时间之后,当server端检测到client端的关闭操作(read返回为0)。接收到文件结束符的server端调用close关闭它的socket。这导致server端的TCP也发送一个FIN N;此时server的状态为LAST_ACK。

    • 4) 客户端A发回ACK报文确认: 当client收到来自server的FIN后 。 client端的套接字处于TIME_WAIT状态,它会向server端再发送一个ack确认,此时server端收到ack确认后,此套接字处于CLOSED状态。

    这样每个方向上都有一个FIN和ACK。

     

    2、四次握手关闭连接的具体状态

        1)FIN-WAIT-1:

          等待远程TCP连接中断请求,或先前的连接中断请求的确认

           主动关闭(active close)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态./* The socket is closed, and the connection is shutting down. 等待远程TCP的连接中断请求,或先前的连接中断请求的确认 */

          如果服务器出现shutdown再重启,使用netstat -nat查看,就会看到很多FIN-WAIT-1的状态。就是因为服务器当前有很多客户端连接,直接关闭服务器后,无法接收到客户端的ACK。


        2)FIN-WAIT-2:从远程TCP等待连接中断请求

           主动关闭端接到ACK后,就进入了FIN-WAIT-2 ./* Connection is closed, and the socket is waiting for a shutdown from the remote end. 从远程TCP等待连接中断请求 */

            这就是著名的半关闭的状态了,这是在关闭连接时,客户端和服务器两次握手之后的状态。在这个状态下,应用程序还有接受数据的能力,但是已经无法发送数据,但是也有一种可能是,客户端一直处于FIN_WAIT_2状态,而服务器则一直处于WAIT_CLOSE状态,而直到应用层来决定关闭这个状态。


         3)CLOSE-WAIT:等待从本地用户发来的连接中断请求

             被动关闭(passive close)端TCP接到FIN后,就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序),并进入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待从本地用户发来的连接中断请求 */

          
        4)CLOSING:等待远程TCP对连接中断的确认

    比较少见./* Both sockets are shut down but we still don't have all our data sent. 等待远程TCP对连接中断的确认 */

    实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示一方发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?
    有两种情况可能导致这种状态:
    其一,如果双方几乎在同时关闭连接,那么就可能出现双方同时发送FIN包的情况;
    其二,如果ACK包丢失而对方的FIN包很快发出,也会出现FIN先于ACK到达。

     

        4)LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认

    被动关闭端一段时间后,接收到文件结束符的应用程序将调用CLOSE关闭连接。这导致它的TCP也发送一个 FIN,等待对方的ACK.就进入了LAST-ACK . /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原来发向远程TCP的连接中断请求的确认 */

    使用并发压力测试的时候,突然断开压力测试客户端,服务器会看到很多LAST-ACK。


        5)TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认

              在主动关闭端接收到FIN后,TCP就发送ACK包,并进入TIME-WAIT状态。/* The socket is waiting after close to handle packets still in the network.等待足够的时间以确保远程TCP接收到连接中断请求的确认 */

             TIME_WAIT等待状态,这个状态又叫做2MSL状态,说的是在TIME_WAIT2发送了最后一个ACK数据报以后,要进入TIME_WAIT状态,这个状态是防止最后一次握手的数据报没有传送到对方那里而准备的(注意这不是四次握手,这是第四次握手的保险状态)。这个状态在很大程度上保证了双方都可以正常结束。

            由于插口的2MSL状态(插口是IP和端口对的意思,socket),使得应用程序在2MSL时间内是无法再次使用同一个插口的,对于客户程序还好一些,但是对于服务程序,例如httpd,它总是要使用同一个端口来进行服务,而在2MSL时间内,启动httpd就会出现错误(插口被使用)。为了避免这个错误,服务器给出了一个平静时间的概念,这是说在2MSL时间内,虽然可以重新启动服务器,但是这个服务器还是要平静的等待2MSL时间的过去才能进行下一次连接。

              详情请看:TIME_WAIT引起Cannot assign requested address报错
     

      6)CLOSED:没有任何连接状态

    被动关闭端在接受到ACK包后,就进入了closed的状态。连接结束./* The socket is not being used. 没有任何连接状态 */

     

    四、TCP状态迁移路线图


    client/server两条路线讲述TCP状态迁移路线图:

     

           这是一个看起来比较复杂的状态迁移图,因为它包含了两个部分---服务器的状态迁移和客户端的状态迁移,如果从某一个角度出发来看这个图,就会清晰许多,这里面的服务器和客户端都不是绝对的,发送数据的就是客户端,接受数据的就是服务器。

    客户端应用程序的状态迁移图

            客户端的状态可以用如下的流程来表示:

            CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

             以上流程是在程序正常的情况下应该有的流程,从书中的图中可以看到,在建立连接时,当客户端收到SYN报文的ACK以后,客户端就打开了数据交互地连接。而结束连接则通常是客户端主动结束的,客户端结束应用程序以后,需要经历FIN_WAIT_1,FIN_WAIT_2等状态,这些状态的迁移就是前面提到的结束连接的四次握手。

    服务器的状态迁移图

            服务器的状态可以用如下的流程来表示:

             CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

            在建立连接的时候,服务器端是在第三次握手之后才进入数据交互状态,而关闭连接则是在关闭连接的第二次握手以后(注意不是第四次)。而关闭以后还要等待客户端给出最后的ACK包才能进入初始的状态。
     

    其他状态迁移

    还有一些其他的状态迁移,这些状态迁移针对服务器和客户端两方面的总结如下

    LISTEN->SYN_SENT,对于这个解释就很简单了,服务器有时候也要打开连接的嘛。

    SYN_SENT->SYN收到,服务器和客户端在SYN_SENT状态下如果收到SYN数据报,则都需要发送SYN的ACK数据报并把自己的状态调整到SYN收到状态,准备进入ESTABLISHED

    SYN_SENT->CLOSED,在发送超时的情况下,会返回到CLOSED状态。

    SYN_收到->LISTEN,如果受到RST包,会返回到LISTEN状态。

    SYN_收到->FIN_WAIT_1,这个迁移是说,可以不用到ESTABLISHED状态,而可以直接跳转到FIN_WAIT_1状态并等待关闭。

     

    怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻的认识,不能只停留在一知半解之中。下面对这张图的11种状态详细解析一下,以便加强记忆!不过在这之前,先回顾一下TCP建立连接的三次握手过程,以及关闭连接的四次握手过程。

     

    五、具体问题


    1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

            这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

    2、什么是2MSL

    MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为tcp报文(segment)是ip数据报(datagram)的数据部分,具体称谓请参见《数据在网络各层中的称呼》一文,而ip头中有一个TTL域,TTL是time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个ip数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

        2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

    这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样):

    一方面是可靠的实现TCP全双工连接的终止,也就是当最后的ACK丢失后,被动关闭端会重发FIN,因此主动关闭端需要维持状态信息,以允许它重新发送最终的ACK。

    另一方面,但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

    TCP在2MSL等待期间,定义这个连接(4元组)不能再使用,任何迟到的报文都会丢弃。设想如果没有2MSL的限制,恰好新到的连接正好满足原先的4元组,这时候连接就可能接收到网络上的延迟报文就可能干扰最新建立的连接。

     

    3.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

    第一,保证可靠的实现TCP全双工链接的终止:为了保证主动端A发送的最后一个ACK报文能够到达被动段B,确保被动端能进入CLOSED状态。

    对照上图,在四次挥手协议中,当B向A发送Fin+Ack后,A就需要向B发送ACK+Seq报文,A这时候就处于TIME_WAIT 状态,但是这个报文ACK有可能会发送失败而丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认。B会超时重传这个FIN+ACK报文段,而A就能在2MSL时间内收到这个重传的FIN+ACK报文段。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后就立即释放连接,就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段。这样B就无法按照正常的步骤进入CLOSED状态。


    第二,防止已失效的连接请求报文段出现在本连接中。A在发送完ACK报文段后,再经过2MSL时间,就可以使本连接持续的时间所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求的报文段。

    假设在A的XXX1端口和B的80端口之间有一个TCP连接。我们关闭这个连接,过一段时间后在相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连 接已经终止后再现,从而被误解成属于同一链接的某一个某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然 TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活msl秒即被丢弃,另一个方向上的应答最多存活msl秒也被丢弃。 通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。

     

     

    4、解决linux发现系统存在大量TIME_WAIT状态

    如果linux发现系统存在大量TIME_WAIT状态的连接,可以通过调整内核参数解决:vi /etc/sysctl.conf 加入以下内容:
    net.ipv4.tcp_max_tw_buckets=5000 #TIME-WAIT Socket 最大数量
    #注意:不建议开启該设置,NAT 模式下可能引起连接 RST
    net.ipv4.tcp_tw_reuse = 1 #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
    net.ipv4.tcp_tw_recycle = 1 #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
     然后执行 /sbin/sysctl -p 让参数生效。

     

     

    六. TCP的FLAGS说明


    在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.
    其中,对于我们日常的分析有用的就是前面的五个字段。
    一、字段含义:
    1、SYN表示建立连接:

    步序列编号(Synchronize Sequence Numbers)栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。

    2、FIN表示关闭连接:
    3、ACK表示响应:

    确认编号(Acknowledgement Number)栏有效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1,Figure-1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。

    4、PSH表示有DATA数据传输:

       
    5、RST表示连接重置:  复位标志有效。用于复位相应的TCP连接。

    一、字段组合含义:

    其中,ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,
    如果只是单个的一个SYN,它表示的只是建立连接。
    TCP的几次握手就是通过这样的ACK表现出来的。
    但SYN与FIN是不会同时为1的,因为前者表示的是建立连接,而后者表示的是断开连接。
    RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。
    一般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;

      RST与ACK标志位都置一了,并且具有ACK number,非常明显,这个报文在释放TCP连接的同时,完成了对前面已接收报文的确认。

    而当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接。
    PSH为1的情况,一般只出现在 DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。
    TCP的连接建立和连接关闭,都是通过请求-响应的模式完成的。

     

    七. TCP通信中服务器处理客户端意外断开


         引用地址:http://blog.csdn.net/kkkkkxiaofei/article/details/12966407

          如果TCP连接被对方正常关闭,也就是说,对方是正确地调用了closesocket(s)或者shutdown(s)的话,那么上面的Recv或Send调用就能马上返回,并且报错。这是由于close socket(s)或者shutdown(s)有个正常的关闭过程,会告诉对方“TCP连接已经关闭,你不需要再发送或者接受消息了”。

    但是,如果意外断开,客户端(3g的移动设备)并没有正常关闭socket。双方并未按照协议上的四次挥手去断开连接。

    那么这时候正在执行Recv或Send操作的一方就会因为没有任何连接中断的通知而一直等待下去,也就是会被长时间卡住。

           像这种如果一方已经关闭或异常终止连接,而另一方却不知道,我们将这样的TCP连接称为半打开的。

           解决意外中断办法都是利用保活机制。而保活机制分又可以让底层实现也可自己实现。

         1、自己编写心跳包程序

         简单的说也就是在自己的程序中加入一条线程,定时向对端发送数据包,查看是否有ACK,如果有则连接正常,没有的话则连接断开

         2、启动TCP编程里的keepAlive机制

     

    一、双方拟定心跳(自实现)

         一般由客户端发送心跳包,服务端并不回应心跳,只是定时轮询判断一下与上次的时间间隔是否超时(超时时间自己设定)。服务器并不主动发送是不想增添服务器的通信量,减少压力。

    但这会出现三种情况:

    情况1.

           客户端由于某种网络延迟等原因很久后才发送心跳(它并没有断),这时服务器若利用自身设定的超时判断其已经断开,而后去关闭socket。若客户端有重连机制,则客户端会重新连接。若不确定这种方式是否关闭了原本正常的客户端,则在ShutDown的时候一定要选择send,表示关闭发送通道,服务器还可以接收一下,万一客户端正在发送比较重要的数据呢,是不?

    情况2.

           客户端很久没传心跳,确实是自身断掉了。在其重启之前,服务端已经判断出其超时,并主动close,则四次挥手成功交互。

    情况3.

          客户端很久没传心跳,确实是自身断掉了。在其重启之前,服务端的轮询还未判断出其超时,在未主动close的时候该客户端已经重新连接。

           这时候若客户端断开的时候发送了FIN包,则服务端将会处于CLOSE_WAIT状态;

           这时候若客户端断开的时候未发送FIN包,则服务端处还是显示ESTABLISHED状态;

           而新连接上来的客户端(也就是刚才断掉的重新连上来了)在服务端肯定是ESTABLISHED;这时候就有个问题,若利用轮询还未检测出上条旧连接已经超时(这很正常,timer总有个间隔吧),而在这时,客户端又重复的上演情况3,那么服务端将会出现大量的假的ESTABLISHED连接和CLOSE_WAIT连接。

            最终结果就是新的其他客户端无法连接上来,但是利用netstat还是能看到一条连接已经建立,并显示ESTABLISHED,但始终无法进入程序代码。个人最初感觉导致这种情况是因为假的ESTABLISHED连接和CLOSE_WAIT连接会占用较大的系统资源,程序无法再次创建连接(因为每次我发现这个问题的时候我只连了10个左右客户端却已经有40多条无效连接)。而最近几天测试却发现有一次程序内只连接了2,3个设备,但是有8条左右的虚连接,此时已经连接不了新客户端了。这时候我就觉得我想错了,不可能这几条连接就占用了大量连接把,如果说几十条还有可能。但是能肯定的是,这个问题的产生绝对是设备在不停的重启,而服务器这边又是简单的轮询,并不能及时处理,暂时还未能解决。

     

    二、利用KeepAlive

              其实keepalive的原理就是TCP内嵌的一个心跳包,

             以服务器端为例,如果当前server端检测到超过一定时间(默认是 7,200,000 milliseconds,也就是2个小时)没有数据传输,那么会向client端发送一个keep-alive packet(该keep-alive packet就是ACK和当前TCP序列号减一的组合),此时client端应该为以下三种情况之一:

            1. client端仍然存在,网络连接状况良好。此时client端会返回一个ACK。server端接收到ACK后重置计时器(复位存活定时器),在2小时后再发送探测。如果2小时内连接上有数据传输,那么在该时间基础上向后推延2个小时。

            2. 客户端异常关闭,或是网络断开。在这两种情况下,client端都不会响应。服务器没有收到对其发出探测的响应,并且在一定时间(系统默认为1000 ms)后重复发送keep-alive packet,并且重复发送一定次数(2000 XP 2003 系统默认为5次, Vista后的系统默认为10次)。

             3. 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。

           对于应用程序来说,2小时的空闲时间太长。因此,我们需要手工开启Keepalive功能并设置合理的Keepalive参数。

    全局设置可更改/etc/sysctl.conf,加上:
    net.ipv4.tcp_keepalive_intvl = 20
    net.ipv4.tcp_keepalive_probes = 3
    net.ipv4.tcp_keepalive_time = 60

    在程序中设置如下:

     #include <sys/socket.h>
      #include <netinet/in.h>
      #include <arpa/inet.h>
      #include <sys/types.h>
      #include <netinet/tcp.h>
    
      int keepAlive = 1; // 开启keepalive属性
      int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测 
      int keepInterval = 5; // 探测时发包的时间间隔为5 秒
      int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.
    
      setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
      setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
      setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
      setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount)); 


    在程序中表现为,当tcp检测到对端socket不再可用时(不能发出探测包,或探测包没有收到ACK的响应包),select会返回socket可读,并且在recv时返回-1,同时置上errno为ETIMEDOUT.

     

    八. Linux错误信息(errno)列表


    经常出现的错误:

    22:参数错误,比如ip地址不合法,没有目标端口等

    101:网络不可达,比如不能ping通

    111:链接被拒绝,比如目标关闭链接等

    115:当链接设置为非阻塞时,目标没有及时应答,返回此错误,socket可以继续使用。比如socket连接

    附录:Linux的错误码表(errno table)

    _ 124 EMEDIUMTYPE_ Wrong medium type
    _ 123 ENOMEDIUM__ No medium found
    _ 122 EDQUOT___  Disk quota exceeded
    _ 121 EREMOTEIO__ Remote I/O error
    _ 120 EISNAM___  Is a named type file
    _ 119 ENAVAIL___ No XENIX semaphores available
    _ 118 ENOTNAM___ Not a XENIX named type file
    _ 117 EUCLEAN___ Structure needs cleaning
    _ 116 ESTALE___  Stale NFS file handle
    _ 115 EINPROGRESS  +Operation now in progress

    操作正在进行中。一个阻塞的操作正在执行。


    _ 114 EALREADY__  Operation already in progress
    _ 113 EHOSTUNREACH  No route to host
    _ 112 EHOSTDOWN__ Host is down
    _ 111 ECONNREFUSED  Connection refused

    1、拒绝连接。一般发生在连接建立时。

    拔服务器端网线测试,客户端设置keep alive时,recv较快返回0, 先收到ECONNREFUSED (Connection refused)错误码,其后都是ETIMEOUT。

    2、an error returned from connect(), so it can only occur in a client (if a client is defined as the party that initiates the connection


    _ 110 ETIMEDOUT_  +Connection timed out
    _ 109 ETOOMANYREFS  Too many references: cannot splice
    _ 108 ESHUTDOWN__ Cannot send after transport endpoint shutdown
    _ 107 ENOTCONN__  Transport endpoint is not connected

    在一个没有建立连接的socket上,进行read,write操作会返回这个错误。出错的原因是socket没有标识地址。Setsoc也可能会出错。

    还有一种情况就是收到对方发送过来的RST包,系统已经确认连接被断开了。


    _ 106 EISCONN___ Transport endpoint is already connected

    一般是socket客户端已经连接了,但是调用connect,会引起这个错误。


    _ 105 ENOBUFS___ No buffer space available
    _ 104 ECONNRESET_  Connection reset by peer

    连接被远程主机关闭。有以下几种原因:远程主机停止服务,重新启动;当在执行某些操作时遇到失败,因为设置了“keep alive”选项,连接被关闭,一般与ENETRESET一起出现。

     

    1、在客户端服务器程序中,客户端异常退出,并没有回收关闭相关的资源,服务器端会先收到ECONNRESET错误,然后收到EPIPE错误。

    2、连接被远程主机关闭。有以下几种原因:远程主机停止服务,重新启动;当在执行某些操作时遇到失败,因为设置了“keep alive”选项,连接被关闭,一般与ENETRESET一起出现。

    3、远程端执行了一个“hard”或者“abortive”的关闭。应用程序应该关闭socket,因为它不再可用。当执行在一个UDP socket上时,这个错误表明前一个send操作返回一个ICMP“port unreachable”信息。

    4、如果client关闭连接,server端的select并不出错(不返回-1,使用select对唯一一个socket进行non- blocking检测),但是写该socket就会出错,用的是send.错误号:ECONNRESET.读(recv)socket并没有返回错误。

    5、该错误被描述为“connection reset by peer”,即“对方复位连接”,这种情况一般发生在服务进程较客户进程提前终止。

     

        主动关闭调用过程如下:

       服务器端主动关闭:

       1)当服务器的服务因为某种原因,进程提前终止时会向客户 TCP 发送 FIN 分节,服务器端处于FIN_WAIT1状态。

       2)客户TCP回应ACK后,服务TCP将转入FIN_WAIT2状态。

       3)此时如果客户进程没有处理该 FIN (如阻塞在其它调用上而没有关闭 Socket 时),则客户TCP将处于CLOSE_WAIT状态。

       4)当客户进程再次向 FIN_WAIT2 状态的服务 TCP 发送数据时,则服务 TCP 将立刻响应 RST。

      一般来说,这种情况还可以会引发另外的应用程序异常,客户进程在发送完数据后,往往会等待从网络IO接收数据,很典型的如 read 或 readline 调用,此时由于执行时序的原因,如果该调用发生在RST分节收到前执行的话,那么结果是客户进程会得到一个非预期的 EOF 错误。此时一般会输出“server terminated prematurely”-“服务器过早终止”错误。


    _ 103 ECONNABORTED  Software caused connection abort

     

    1、软件导致的连接取消。一个已经建立的连接被host方的软件取消,原因可能是数据传输超时或者是协议错误。

    2、该错误被描述为“software caused connection abort”,即“软件引起的连接中止”。原因在于当服务和客户进程在完成用于 TCP 连接的“三次握手”后,客户 TCP 却发送了一个 RST (复位)分节,在服务进程看来,就在该连接已由 TCP 排队,等着服务进程调用 accept 的时候 RST 却到达了。POSIX 规定此时的 errno 值必须 ECONNABORTED。源自 Berkeley 的实现完全在内核中处理中止的连接,服务进程将永远不知道该中止的发生。服务器进程一般可以忽略该错误,直接再次调用accept。

    当TCP协议接收到RST数据段,表示连接出现了某种错误,函数read将以错误返回,错误类型为ECONNERESET。并且以后所有在这个套接字上的读操作均返回错误。错误返回时返回值小于0。


    _ 102 ENETRESET__ Network dropped connection on reset

     

    网络重置时丢失连接。

    由于设置了"keep-alive"选项,探测到一个错误,连接被中断。在一个已经失败的连接上试图使用setsockopt操作,也会返回这个错误。


    _ 101 ENETUNREACH_ Network is unreachable

     

    络不可达。Socket试图操作一个不可达的网络。这意味着local的软件知道没有路由到达远程的host。
    _ 100 ENETDOWN__  Network is down

    _  99 EADDRNOTAVAIL Cannot assign requested address
    _  98 EADDRINUSE_  Address already in use
    _  97 EAFNOSUPPORT  Address family not supported by protocol
    _  96 EPFNOSUPPORT  Protocol family not supported
    _  95 EOPNOTSUPP_  Operation not supported
    _  94 ESOCKTNOSUPPORT Socket type not supported

    Socket类型不支持。指定的socket类型在其address family中不支持。如可选选中选项SOCK_RAW,但实现并不支持SOCK_RAW sockets。


    _  93 EPROTONOSUPPORT Protocol not supported

    不支持的协议。系统中没有安装标识的协议,或者是没有实现。如函数需要SOCK_DGRAM socket,但是标识了stream protocol.。


    _  92 ENOPROTOOPT_ Protocol not available

    该错误不是一个 Socket 连接相关的错误。errno 给出该值可能由于,通过 getsockopt 系统调用来获得一个套接字的当前选项状态时,如果发现了系统不支持的选项参数就会引发该错误。
    _  91 EPROTOTYPE_  Protocol wrong type for socket

     

    协议类型错误。标识了协议的Socket函数在不支持的socket上进行操作。如ARPA Internet

    UDP协议不能被标识为SOCK_STREAM socket类型。


    _  90 EMSGSIZE__ +Message too long

     

    消息体太长。

    发送到socket上的一个数据包大小比内部的消息缓冲区大,或者超过别的网络限制,或是用来接收数据包的缓冲区比数据包本身小。


    _  89 EDESTADDRREQ  Destination address required

     

    需要提供目的地址。

    在一个socket上的操作需要提供地址。如往一个ADDR_ANY 地址上进行sendto操作会返回这个错误。


    _  88 ENOTSOCK__  Socket operation on non-socket

    在非socket上执行socket操作。


    _  87 EUSERS___  Too many users
    _  86 ESTRPIPE__  Streams pipe error
    _  85 ERESTART__  Interrupted system call should be restarted
    _  84 EILSEQ___  Invalid or incomplete multibyte or wide character
    _  83 ELIBEXEC__  Cannot exec a shared library directly
    _  82 ELIBMAX___ Attempting to link in too many shared libraries
    _  81 ELIBSCN___ .lib section in a.out corrupted
    _  80 ELIBBAD___ Accessing a corrupted shared library
    _  79 ELIBACC___ Can not access a needed shared library
    _  78 EREMCHG___ Remote address changed
    _  77 EBADFD___  File descriptor in bad state
    _  76 ENOTUNIQ__  Name not unique on network
    _  75 EOVERFLOW__ Value too large for defined data type
    _  74 EBADMSG__  +Bad message
    _  73 EDOTDOT___ RFS specific error
    _  72 EMULTIHOP__ Multihop attempted
    _  71 EPROTO___  Protocol error
    _  70 ECOMM____ Communication error on send
    _  69 ESRMNT___  Srmount error
    _  68 EADV____  Advertise error
    _  67 ENOLINK___ Link has been severed
    _  66 EREMOTE___ Object is remote
    _  65 ENOPKG___  Package not installed
    _  64 ENONET___  Machine is not on the network
    _  63 ENOSR____ Out of streams resources
    _  62 ETIME____ Timer expired
    _  61 ENODATA___ No data available
    _  60 ENOSTR___  Device not a stream
    _  59 EBFONT___  Bad font file format
    _  57 EBADSLT___ Invalid slot
    _  56 EBADRQC___ Invalid request code
    _  55 ENOANO___  No anode
    _  54 EXFULL___  Exchange full
    _  53 EBADR____ Invalid request descriptor
    _  52 EBADE____ Invalid exchange
    _  51 EL2HLT___  Level 2 halted
    _  50 ENOCSI___  No CSI structure available
    _  49 EUNATCH___ Protocol driver not attached
    _  48 ELNRNG___  Link number out of range
    _  47 EL3RST___  Level 3 reset
    _  46 EL3HLT___  Level 3 halted
    _  45 EL2NSYNC__  Level 2 not synchronized
    _  44 ECHRNG___  Channel number out of range
    _  43 EIDRM____ Identifier removed
    _  42 ENOMSG___  No message of desired type
    _  40 ELOOP____ Too many levels of symbolic links
    _  39 ENOTEMPTY_  +Directory not empty
    _  38 ENOSYS___ +Function not implemented
    _  37 ENOLCK___ +No locks available
    _  36 ENAMETOOLONG +File name too long
    _  35 EDEADLK__  +Resource deadlock avoided
    _  34 ERANGE___ +Numerical result out of range
    _  33 EDOM____ +Numerical argument out of domain
    _  32 EPIPE___  +Broken pipe

    接收端关闭(缓冲中没有多余的数据),但是发送端还在write:

    1、Socket 关闭,但是socket号并没有置-1。继续在此socket上进行send和recv,就会返回这种错误。这个错误会引发SIGPIPE信号,系统会将产生此EPIPE错误的进程杀死。所以,一般在网络程序中,首先屏蔽此消息,以免发生不及时设置socket进程被杀死的情况。

    2、write(..) on a socket that has been closed at the other end will cause a SIGPIPE.

    3、错误被描述为“broken pipe”,即“管道破裂”,这种情况一般发生在客户进程不理会(或未及时处理)Socket 错误,继续向服务 TCP 写入更多数据时,内核将向客户进程发送 SIGPIPE 信号,该信号默认会使进程终止(此时该前台进程未进行 core dump)。结合上边的 ECONNRESET 错误可知,向一个 FIN_WAIT2 状态的服务 TCP(已 ACK 响应 FIN 分节)写入数据不成问题,但是写一个已接收了 RST 的 Socket 则是一个错误。


    _  31 EMLINK___ +Too many links
    _  30 EROFS___  +Read-only file system
    _  29 ESPIPE___ +Illegal seek
    _  28 ENOSPC___ +No space left on device
    _  27 EFBIG___  +File too large
    _  26 ETXTBSY___ Text file busy
    _  25 ENOTTY___ +Inappropriate ioctl for device
    _  24 EMFILE___ +Too many open files

    打开了太多的socket。对进程或者线程而言,每种实现方法都有一个最大的可用socket数目处理,或者是全局的,或者是局部的。

    _  23 ENFILE___ +Too many open files in system
    _  22 EINVAL___ +Invalid argument

    无效参数。提供的参数非法。有时也会与socket的当前状态相关,如一个socket并没有进入listening状态,此时调用accept,就会产生EINVAL错误。


    _  21 EISDIR___ +Is a directory
    _  20 ENOTDIR__  +Not a directory
    _  19 ENODEV___ +No such device
    _  18 EXDEV___  +Invalid cross-device link
    _  17 EEXIST___ +File exists
    _  16 EBUSY___  +Device or resource busy
    _  15 ENOTBLK___ Block device required
    _  14 EFAULT___ +Bad address地址错误
    _  13 EACCES___ +Permission denied
    _  12 ENOMEM___ +Cannot allocate memory
    _  11 EAGAIN___ +Resource temporarily unavailable

    在读数据的时候,没有数据在底层缓冲的时候会遇到,一般的处理是循环进行读操作,异步模式还会等待读事件的发生再读

     

       1、Send返回值小于要发送的数据数目,会返回EAGAIN和EINTR。

       2、recv 返回值小于请求的长度时说明缓冲区已经没有可读数据,但再读不一定会触发EAGAIN,有可能返回0表示TCP连接已被关闭。

       3、当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,可以做延时后再重试.

       4、在Linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),表明在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。对非阻塞socket而言,EAGAIN不是一种错误。


    _  10 ECHILD___ +No child processes
    __ 9 EBADF___  +Bad file descriptor
    __ 8 ENOEXEC__  +Exec format error
    __ 7 E2BIG___  +Argument list too long
    __ 6 ENXIO___  +No such device or address
    __ 5 EIO____  +Input/output error
    __ 4 EINTR___  +Interrupted system call

     

        阻塞的操作被取消阻塞的调用打断。如设置了发送接收超时,就会遇到这种错误。

        只能针对阻塞模式的socket。读,写阻塞的socket时,-1返回,错误号为INTR。另外,如果出现EINTR即errno为4,错误描述Interrupted system call,操作也应该继续。如果recv的返回值为0,那表明连接已经断开,接收操作也应该结束。


    __ 3 ESRCH___  +No such process
    __ 2 ENOENT___ +No such file or directory
    __ 1 EPERM___  +Operation not permitted

     

     

    展开全文
  • TCP连接、Http连接与Socket连接的区别

    千次阅读 多人点赞 2019-06-08 17:45:32
    文章目录HTTP、Socket、TCP的区别Socket(套接字)Socket长连接什么时候用长连接,短连接TCP连接和HTTP连接的区别TCP连接与Socket连接的区别HTTP连接与Socket连接的区别常见问题什么时候该用HTTP,什么时候该用...

    HTTP、Socket、TCP的区别

    这三个概念经常被谈到,也是比较容易被混掉的概念。在回顾之前我们先看一下这三者在TCP/IP协议族中的位置关系:
    这里写图片描述
    在这里插入图片描述
    HTTP是应用层的协议,更靠近用户端;TCP是传输层的协议;而socket是从传输层上抽象出来的一个抽象层,本质是接口。所以本质上三种还是很好区分的。

    Socket(套接字)

    现在我们了解到TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。就像操作系统会提供标准的编程接口,比如Win32编程接口一样,TCP/IP也必须对外提供编程接口,这就是Socket。现在我们知道,Socket跟TCP/IP并没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以,Socket的出现只是可以更方便的使用TCP/IP协议栈而已,其对TCP/IP进行了抽象,形成了几个最基本的函数接口。比如create,listen,accept,connect,read和write等等,不同语言都有对应的建立Socket服务端和客户端的库。

    Socket长连接

    所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接(心跳包),一般需要自己做在线维持。 短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接。比如Http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。其实长连接是相对于通常的短连接而说的,也就是长时间保持客户端与服务端的连接状态。
    通常的短连接操作步骤是:
    连接→数据传输→关闭连接;

    而长连接通常就是:
    连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接;

    什么时候用长连接,短连接

    长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理 速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成Socket错误,而且频繁的Socket创建也是对资源的浪费。

    TCP连接和HTTP连接的区别

    HTTP是基于TCP的,客户端往服务端发送一个HTTP请求时第一步就是要建立与服务端的TCP连接,也就是先三次握手,“你好,你好,你好”。从HTTP 1.1开始支持持久连接,也就是一次TCP连接可以发送多次的HTTP请求。
    总结:HTTP基于TCP

    TCP连接与Socket连接的区别

    socket层只是在TCP/UDP传输层上做的一个抽象接口层,因此一个socket连接可以基于连接,也有可能基于UDP。基于TCP协议的socket连接同样需要通过三次握手建立连接,是可靠的;基于UDP协议的socket连接不需要建立连接的过程,不过对方能不能收到都会发送过去,是不可靠的,大多数的即时通讯IM都是后者。

    总结:Socket也基于TCP,socket 是实现TCP,UDP的。类似于jedis(redis的java实现)和redis的关系。

    HTTP连接与Socket连接的区别

    区分这两个概念是比较有意义的,毕竟TCP看不见摸不着,HTTP与Socket是实实在在能用到的。

    HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。

    HTTP连接服务端无法主动发消息,Socket连接双方请求的发送先后限制。这点就比较重要了,因为它将决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,在客户端还没发送消息给服务端前,服务端无法推送消息给客户端。必须满足客户端发送消息在前,服务端回复在后。Socket连接双方类似peer2peer的关系,一方随时可以向另一方喊话。

    常见问题

    什么时候该用HTTP,什么时候该用socket ?

    这个问题的提出是很自然而然的。当你接到一个与另一方的网络通讯需求,自然会考虑用HTTP还是用Socket。

    用HTTP的情况:双方不需要时刻保持连接在线,比如客户端资源的获取、文件上传等。
    用Socket的情况:大部分即时通讯应用(QQ、微信)、聊天室、苹果APNs等。

    浏览器在与服务器建立了一个 TCP 连接后是否会在一个 HTTP 请求完成后断开?什么情况下会断开?

    在 HTTP/1.0 中,一个服务器在发送完一个 HTTP 响应后,会断开 TCP 链接。但是这样每次请求都会重新建立和断开 TCP 连接,代价过大。所以虽然标准中没有设定,某些服务器对 Connection: keep-alive 的 Header 进行了支持。意思是说,完成这个 HTTP 请求之后,不要断开 HTTP 请求使用的 TCP 连接。这样的好处是连接可以被重新使用,之后发送 HTTP 请求的时候不需要重新建立 TCP 连接,以及如果维持连接,那么 SSL 的开销也可以避免,两张图片是我短时间内两次访问 https://www.github.com 的时间统计:
    在这里插入图片描述
    头一次访问,有初始化连接和 SSL 开销
    在这里插入图片描述
    初始化连接和 SSL 开销消失了,说明使用的是同一个 TCP 连接
    持久连接:既然维持 TCP 连接好处这么多,HTTP/1.1 就把 Connection 头写进标准,并且默认开启持久连接,除非请求中写明 Connection: close,那么浏览器和服务器之间是会维持一段时间的 TCP 连接,不会一个请求结束就断掉。

    所以结论是:默认情况下建立 TCP 连接不会断开,只有在请求报头中声明 Connection: close 才会在请求完成后关闭连接

    一个TCP 连接可以发多少个 HTTP 请求?

    了解了上一个问题之后,其实这个问题已经有了答案,如果维持连接,一个 TCP 连接是可以发送多个 HTTP 请求的。maxKeepAliveRequests: 每个TCP连接接受最大的Http请求数目,当处理一个keep alive请求达到这个最大值,Tomcat关闭这个连接,设置为失效任何keep alive请求.

    一个 TCP 连接中 HTTP 请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?

    HTTP/1.1 存在一个问题,单个 TCP 连接在同一时刻只能处理一个请求,意思是说:两个请求的生命周期不能重叠,任意两个 HTTP 请求从开始到结束的时间在同一个 TCP 连接里不能重叠。

    虽然 HTTP/1.1 规范中规定了 Pipelining 来试图解决这个问题,但是这个功能在浏览器中默认是关闭的。

    先来看一下 Pipelining 是什么,RFC 2616 中规定了:

    A client that supports persistent connections MAY "pipeline" its requests (i.e., send multiple requests without waiting for each response). A server MUST send its responses to those requests in the same order that the requests were received.
    一个支持持久连接的客户端可以在一个连接中发送多个请求(不需要等待任意请求的响应)。收到请求的服务器必须按照请求收到的顺序发送响应。
    

    至于标准为什么这么设定,我们可以大概推测一个原因:由于 HTTP/1.1 是个文本协议,同时返回的内容也并不能区分对应于哪个发送的请求,所以顺序必须维持一致。比如你向服务器发送了两个请求 GET/query?q=A 和 GET/query?q=B,服务器返回了两个结果,浏览器是没有办法根据响应结果来判断响应对应于哪一个请求的。

    Pipelining 这种设想看起来比较美好,但是在实践中会出现许多问题:

    • 一些代理服务器不能正确的处理 HTTP Pipelining。
    • 正确的流水线实现是复杂的。
    • Head-of-line Blocking 连接头阻塞:在建立起一个 TCP 连接之后,假设客户端在这个连接连续向服务器发送了几个请求。按照标准,服务器应该按照收到请求的顺序返回结果,假设服务器在处理首个请求时花费了大量时间,那么后面所有的请求都需要等着首个请求结束才能响应。

    所以现代浏览器默认是不开启 HTTP Pipelining 的。

    但是,HTTP2 提供了 Multiplexing 多路传输特性,可以在一个 TCP 连接中同时完成多个 HTTP 请求。至于 Multiplexing 具体怎么实现的就是另一个问题了。我们可以看一下使用 HTTP2 的效果。
    在这里插入图片描述
    绿色是发起请求到请求返回的等待时间,蓝色是响应的下载时间,可以看到都是在同一个 Connection,并行完成的

    所以这个问题也有了答案:在 HTTP/1.1 存在 Pipelining 技术可以完成这个多个请求同时发送,但是由于浏览器默认关闭,所以可以认为这是不可行的。在 HTTP2 中由于 Multiplexing 特点的存在,多个 HTTP 请求可以在同一个 TCP 连接中并行进行

    那么在 HTTP/1.1 时代,浏览器是如何提高页面加载效率的呢?主要有下面两点:

    • 维持和服务器已经建立的 TCP 连接,在同一连接上顺序处理多个请求。
    • 和服务器建立多个 TCP 连接

    为什么有时候刷新页面不需要重新建立 SSL 连接?

    在上面问题的讨论中已经有答案了,TCP 连接有的时候会被浏览器和服务端维持一段时间。TCP 不需要重新建立,SSL 自然也会用之前的。

    浏览器对同一 Host 建立 TCP 连接到数量有没有限制?

    假设我们还处在 HTTP/1.1 时代,那个时候没有多路传输,当浏览器拿到一个有几十张图片的网页该怎么办呢?肯定不能只开一个 TCP 连接顺序下载,那样用户肯定等的很难受,但是如果每个图片都开一个 TCP 连接发 HTTP 请求,那电脑或者服务器都可能受不了,要是有 1000 张图片的话总不能开 1000 个TCP 连接吧,你的电脑同意 NAT 也不一定会同意。

    所以答案是:有。Chrome最多允许对同一个 Host 建立六个 TCP 连接。不同的浏览器有一些区别。

    收到的 HTML 如果包含几十个图片标签,这些图片是以什么方式、什么顺序、建立了多少连接、使用什么协议被下载下来的呢?

    如果图片都是 HTTPS 连接并且在同一个域名下,那么浏览器在 SSL 握手之后会和服务器商量能不能用 HTTP2,如果能的话就使用Multiplexing 功能在这个连接上进行多路传输。不过也未必会所有挂在这个域名的资源都会使用一个 TCP 连接去获取,但是可以确定的是 Multiplexing 很可能会被用到。
    如果发现用不了 HTTP2 呢?或者用不了 HTTPS(现实中的 HTTP2 都是在 HTTPS 上实现的,所以也就是只能使用 HTTP/1.1)。那浏览器就会在一个 HOST 上建立多个 TCP 连接,连接数量的最大限制取决于浏览器设置,这些连接会在空闲的时候被浏览器用来发送新的请求,如果所有的连接都正在发送请求呢?那其他的请求就只能等等了。

    https://developers.google.com/web/tools/chrome-devtools/network/issues#queued-or-stalled-requestsdevelopers.google.com

    参考:
    https://blog.csdn.net/It_sharp/article/details/81532167(TCP连接、Http连接与Socket连接的区别)
    https://segmentfault.com/a/1190000014044351 (一篇搞懂TCP、HTTP、Socket、Socket连接池)
    https://mp.weixin.qq.com/s/TfebZ3-atixL61cjNBjU6w (一个 TCP 连接可以发多少个 HTTP 请求)

    展开全文
  • 一个TCP连接通常分为3个阶段:启动、数据传输(也称为“连接已建立”)、退出 下面我们介绍典型的TCP连接的建立与关闭过程(不包括任何数据传输) 一、TCP连接的建立(三次握手) TCP连接的建立分为3步: 1.主动...

    • 一个TCP连接通常分为3个阶段:启动、数据传输(也称为“连接已建立”)、退出
    • 下面我们介绍典型的TCP连接的建立与关闭过程(不包括任何数据传输)

    一、TCP连接的建立(三次握手)

    TCP连接的建立分为3步:

    • 1.主动开启者(通常称为客户端)发送一个SYN报文段(即一个在TCP头部的SYN位字段置位的TCP/IP数据包),并指明自己想要连接的端口号和它的客户端初始序列号(记为ISN(c),本文下面介绍)。通常,客户端还会借此发送一个或多个选项。客户端发送的这个SYN报文段称作段1
    • 2.服务器也发送自已的SYN报文段作为响应,并包含了它的初始序列号(记作ISN(s))。该段称作段2。此外,为了确认客户端的SYN,服务器将其包含的ISN(c)数值加1后作为返回的ACK数值。因此,每发送一个SYN,序列号就会自动加1。这样如果出现丢失的情况,该SYN段将会重传
    • 3.为了确认服务器的SYN,客户端将ISN(s)的数值加1后作为返回的ACK数值。这称为段3

    • 简化之后如下图所示:(在显示相关状态的同时省略了选项与初始序列号等细节)

    • 通过发送上述3个报文段就能够完成一个TCP连接的建立。它们也常称作三次握手。 三次握手的目的不仅在于让通信双方了解一个连接正在建立,还在于利用数据包的选项来承载特殊的信息,交换初始序列号(Initial Sequence Number。ISN)
    • 发送首个SYN的一方被认为是主动地打开一个连接。如上文所述,它通常是一个客户端。连接的另一方会接收这个SYN,并发送下一个SYN,因此它是被动地打开一个连接。 通常,这一方称为服务器 (后面将会介绍一种客户端与服务器同时打开一个连接的情况,但非常少见)

    二、TCP连接的关闭(四次挥手)

    • 连接的任何一方都能够发起一个关闭操作。此外,该过程还支持双方同时关闭连接的操作,但这种情况非常少见
    • 在传统的情况下,负责发起关闭连接的通常是客户端。然而,一些服务器(例如web服务器)在对请求做出响应之后也会发起一个关闭操作。通常一个关闭操作是由应用程序提出关闭连接的请求而引发的(例如使用系统调用close)
    • TCP协议规定通过发送一个FIN段(即FIN位字段置位的TCP报文段)来发起关闭操作。只有当连接双方都完成关闭操作后,才构成一个完整关闭

    TCP连接的关闭分为4步:

    • 1.连接的主动关闭者发送一个FIN段指明接收者希望看到的自已当前的序列号(K)。FIN段还包含了一个ACK段用于确认对方最近一次发来的数据(标记为L)
    • 2.连接的被动关闭者将K的数值加1作为响应的ACK值,以表明它已经成功接收到主动关闭者发送的FIN。此时,上层的应用程序会被告知连接的另一端已经提出了关闭的请求。通常,这将导致应用程序发起自已的关闭操作
    • 3.接着,被动关闭者将身份转变为主动关闭者,并发送自已的FIN。该报文段的序列号为L
    • 4.为了完成连接的关闭,最后发送的报文段还包含一个ACK用于确认上一个FIN。值得注意的是,如果出现FIN丢失的情况,那么发送方将重新传输直到接收到一个ACK确认为止

    • 简化之后如下图所示:(在显示相关状态的同时省略了选项与初始序列号等细节)

    三、TCP半关闭

    • 如前所述,TCP支持半关闭操作。虽然一些应用需要此项功能,但它并不常见
    • 为了实现这一特性,API必须为应用程序提供一种基本的表达方式。例如,应用程序表明“我已经完成了数据的发送工作,并发送一个FIN给对方,但是我仍然希望接收来自对方的数据直到它发送一个FIN给我” 。伯克利套接字的API提供了半关闭操作。应用程序只需要调用shutdown()函数来代替基本的cIose()函数,就能实现上述操作。然而,绝大部分应用程序仍然会调用close()函数来同时关闭一条连接的两个传输方向
    • shutdown系统调用参阅:https://blog.csdn.net/qq_41453285/article/details/89647130
    • close系统调用参阅:https://blog.csdn.net/qq_41453285/article/details/89179532

    图示

    • 下图展示了一个正在使用的半关闭示例。图中左侧的客户端负责发起半关闭操作,然而在实际应用中,通信的任何一方都能完成这项工作
    • 首先发送的两个报文段与TCP正常关闭完全相同:初始者发送的FIN,接着是接收者回应该FIN的ACK
    • 由于接收到半关闭的一方仍能够发送数据,因此下图中的后续操作与四次挥手关闭连接的情况不同不同。虽然下图在ACK之后只描述了一个数据段的传输过程,但实际应用时可以传输任意数量的数据段(后面“TCP数据流与窗口管理”将会详细地讨论数据段的交换与确认细节)。当接收半关闭的一方完成数据发送后,它将会发送一个FIN来关闭本方的连接,同时向发起半关闭的应用程序发出一个文件尾指示。当第2个FIN被确认之后,整个连接完全关闭

    四、TCP的同时打开

    • 虽然两个应用程序同时主动打开连接看似不大可能,但是在特定安排的情况下是有可能实现的。通信双方在接收到来自对方的SYN之前必须先发送一个SYN;两个SYN必须经过网络送达对方。该场景还要求通信双方都拥有一个IP地址与端口号,并且将其告知对方。 上述情况十分少见(前面文章介绍的防火墙“打孔”技术除外),一旦发生,可称其为同时打开
    • 例如:
      • 主机A的一个应用程序通过本地的7777端口向主机B的8888端口发送一个主动打开请求,与此同时主机B的一个应用程序也通过本地的8888端口向主机A的7777端口提出一个主动打开请求,此时就会发生一个同时打开的情况
      • 这种情况不同于主机A的一个客户端连接主机B的一个服务器,而同时又有主机B的一个客户端连接主机A的一个服务器的情况。在这种情况下,服务器始终是连接的被动打开者而非主动打开者,而备自的客户端也会选择不同的端口号。因此,它们可以被区分为两个不同的TCP连接

    图例

    • 下图显示了在一个同时打开过程中报文段的交换情况
    • 一个同时打开过程需要交换4个报文段,比普通的三次握手增加了一个
    • 由于通信双方都扮演了客户端与服务器的角色,因此不能够将任何一方称作客户端或服务器

    五、TCP的同时关闭

    • 同时关闭与同时连接并没有太大区别
    • 前面的正常关闭过程,通信一方(通常是客户端,但不一定总是)提出主动关闭请求,并发送首个FIN。在同时关闭中,通信双方都会完成上述工作

    图例

    • 下图显示了在一个同时关闭中需要交换的报文段
    • 同时关闭需要交换与正常关闭相同数量的报文段。两者真正的区别在于:报文段序列是交叉的还是顺序的。下文将会介绍TCP实现中同时打开与同时关闭操作使用特殊状态这一不常见的方法

    六、初始化序列号(Seq、ISN)

    为什么要用序列号

    • 当一个连接打开时,任何拥有合适的IP地址、端口号、符合逻辑的序列号(即在窗口中)以及正确校验和的报文段都将被对方接收。然而,这也引人了另一个问题。在一个连接中,TCP报文段在经过网络路由后可能会存在延迟抵达与排序混乱的情况。为了解决这一问题,需要仔细选择初始序列号
    • 在发送用于建立连接的SYN之前,通信双方会选择一个初始序列号。初始序列号会随时间而改变,因此每一个连接都拥有不同的初始序列号
    • [RFCO793]指出初始序列号可被视为一个32位的计数器。该计数器的数值每4微秒加1。此举的目的在于为一个连接的报文段 安排序列号,以防止出现与其他连接的序列号重叠的情况。尤其对于同一连接的两个不同实例而言,新的序列号也不能出现重叠的情况

    序列号重叠问题

    • 由于一个TCP连接是被一对端点所唯一标识的,其中包括由2个IP地址与2个端口号构成的4元组,因此即便是同一个连接也会出现不同的实例。如果连接由于某个报文段的长时间延迟而被关闭,然后又以相同的4元组被重新打开,那么可以相信延迟的报文段又会被视为有效数据重新进入新连接的数据流中
    • 上述情况会令人十分烦恼。通过采取一些步骤来避免连接实例间的序列号重叠问题,能够将风险降至最低。即便如此,一个对数据完整性有较高要求的应用程序也可以在应用层利用CRC或校验和保证所需数据在传输过程中没有出现任何错误。在任何情况下这都是一种很好的方法,并已普遍用于大文件的传输

    序列号带来的攻击

    • 如前文所述,一个TCP报文段只有同时具备连接的4元组与当前活动窗口的序列号,才会在通信过程中被对方认为是正确的。然而,这也从另一个侧面反映了TCP的脆弱性:如果选择合适的序列号、 IP地址以及端口号,那么任何人都能伪造出一个TCP报文段,从而打断TCP的正常连接[RFC5961]
    • 一种抵御上述行为的方法是使初始序列号(或者临时端口号)变得相对难以被猜出,而另一种方法则是加密

    不同系统对序列号的实现

    • 现代系统通常采用半随机的方法选择初始序列号。证书报告CA-2001-09 [CERTISN]讨论了这一方法的具体实现细节
    • Linux系统采用一个相对复杂的过程来选择它的初始序列号。 它采用基于时钟的方案,并且针对每一个连接为时钟设置随机的偏移量。随机偏移量是在连接标识(即4元组)的基础上利用加密散列函数得到的。散列函数的输人每隔5分钟就会改变一次。在32位的初始序列号中,最高的8位是一个保密的序列号,而剩余的备位则由散列函数生成。上述方法所生成的序列号很难被猜出,但依然会随着时间而逐步增加
    • 据报告显示,Windows系统使用了一种基于RC4[S94]的类似方案

    七、TCP连接演示案例

    • 使用telnet工具连接服务器“10.0.0.2:80”

    • telnet命令是建立在TCP连接的基础上的。当Telnet应用程序连接23(Telnet协议的众所周知端口)以外的端口,它将不能用于应用协议。它仅仅将自已的字节输人拷贝至TCP连接中,反之亦然。当一个Web服务器接收到进人的连接请求时,它首先需要等待对web页面的请求。在这种情况下,我们不能提供这样的请求,因此服务器不会产生任何数据。这些均符合我们的期望,因为我们只对连接建立与终止过程中的数据包交换感兴趣

    最终结果

    • 客户端发送的SYN报文段所包含的初始序列号为685506836,广告窗口为65535,该报文段还包含了若干其他选项(选项在后面介绍)
    • 第二个报文段既包含了服务器的SYN还包含了对客户端请求的ACK确认。它的序列号(服务器的初始序列号)为1479690171,ACK号为685506837。ACK号仅比客户端的初始序列号大1,说明服务器已经成功接收到了客户端的初始序列号。该报文段同样也包含了一个广告窗口以表明服务器愿意接收64240个字节。第三个数据包将最终完成三次握手,它的ACK号为1479690172。ACK号是不断累积的,并且总是表明ACK发送者希望接收到的下一个序列号(而不是它上一个接收到的序列号)
    • 在4.4秒暂停之后,Telnet应用程序被要求关闭连接。这使得客户端发送第4个报文段FIN。FIN的序列号为685506837,并由第5个报文段确认(ACK号为685506838)。稍后,服务器会发送自已的FIN,对应的序列号为1479690172。该报文段对客户端的FIN进行了再次确认。值得注意的是,该报文段的PSH位被置位。虽然这样并不会对连接的关闭过程产生实质影响,但通常用于说明服务器将不会再发送任何数据。最后一个报文段用于对服务器的FIN进行确认,ACK号为1479690173

    • 从图中我们还会发现SYN报文段包含了一个或多个选项。这些选项需要占用TCP头部额外的空间。例如,第一个TCP头部的长度为44字节,比最小的长度长24字节。TCP也提供了若干选项,下文将详细介绍当一个连接无法建立时如何使用这些选项

    八、TCP连接建立超时演示案例

    • 本节的若干实例将会展示连接不能建立的情况。一种显而易见的情况是服务器关闭。为了模拟这种情况,我们将telnet命令发送给一个处于同一子网的不存在的主机。在不修改ARP表的情况下,上述做法会使客户端收到一个“无法到达主机”的错误消息后退出。由 于没有接收到针对之前发送的ARP请求而返回的ARP响应,因此会产生“无法到达主机”的消息。如果我们能事先在ARP表中为这个不存在的主机添加一条记录,那 么系统就不需要发送ARP请求,而会马上根据TCP/IP协议尝试与这个不存在的主机建立联系。相关的命令如下:

    • 上述例子选择的MAC地址00:00:1a:1b:1c:1d不能与局域网中其他主机的MAC冲突,除此之外并无特别。超时发生在发送初始命令后的3.2分钟。由于没有主机响应,例子中所 有的报文段都是由客户端产生的。下图显示了使用Wireshark软件在摘要模式下获得的输出结果

    • 有趣的是这些输出结果显示了客户端TCP为了建立连接频繁地发送SYN报文段。在首个报文段发送后仅3秒第二个报文段就被发送出去,第三个报文段则是这之后的6秒,而第四个报文段则在第三个报文段发送12秒以后被发送出去,以此类推。这一行为被称作指数 回退。在讨论以太网CSMA/CD介质访问控制协议时我们也曾见过这样的行为。然而,这两种指数回退也略有不同。此处的每一次回退数值都是前一次数值的两倍,而在以太网中最大的回退数值是上一次的两倍,实际的回退数值则需要随机选取
    • 一些系统可以配置发送初始SYN的次数,但通常选择一个相对较小的数值50。Linux系统中,系统配置变量net.ipv4.tcp_syn_retries表示了在一次主动打开申请中尝试重新发送SYN报文段的最大次数。相应地,变量net.ipv4.tcp_synack_retries表示在响应对方的一个主 动打开请求时尝试重新发送SYN + ACK报文段的最大次数。此外,它能够在设定Linux专有的TCP_SYNCNT套接字选项的基础上用于个人连接。正如上面所介绍的,默认的数值为重试5次。两次重新传输之间的指数回退时间是TCP拥塞管理响应的一部分。当我们讨论 kam算法时再仔细研究

    九、连接与转换器

    • 在前面NAT的文章中,我们已经讨论了一些协议(比如TCP和UDP)如何利用传统的NAT转换地址与端口号。我们还讨论了IP数据包如何在IPv6与IPv4两个版本间进行转换。当TCP使用NAT时,伪头部的校验和通常需要调整(使用校验和中立地址修改器的情况除外)。其他协议也使用伪头部校验和。因为计算包含了与传输层、网络层相关的信息。
    • 当一个TCP连接首次被建立时,NAT能够根据报文段的SYN位探明这一事实。同样,可以通过检查SYN + ACK报文段与ACK报文段所包含的序列号来判断一个连接是否已经完全建立。上述方法还适用于连接的终止。通过在NAT中实现一部分TCP状态机能够跟踪连接,包括当前状态、备方向的序列号以及相关的ACK号。这种状态跟踪是典型的NAT实现方法
    • 当NAT扮演编辑者的角色并且向传输协议的数据负载中写人内容时,就会涉及一些更复杂的问题。对于TCP而言,它将会包括在数据流中添加与删除数据,并由此影响序列号(与报文段)的长度。此举会影响到校验和,但也会影响数据的顺序。如果利用NAT在数据 流中插人或删除数据这些数值都要做出适当调整。如果NAT的状态与终端主机的状态不同步,连接就无法正确进行下去。因此,上述做法会带来一定的脆弱性
    展开全文
  • TCP连接攻击

    千次阅读 2017-02-21 11:56:39
    TCP连接耗尽攻击与防御原理 攻击原理 连接耗尽攻击是指攻击者通过僵尸网络,向服务器发起大量的TCP连接,耗尽服务器的TCP连接资源。连接耗尽一般有以下几种攻击类型: 完成三次握手后,不发送任何...
  • linux查看tcp连接状态

    万次阅读 2019-09-06 12:41:58
    netstat -an |grep tcp 查看所有tcp连接包括LISTEN状态 netstat -an |grep ESTABLISHED 查看所有正在连接中的tcp连接 如果需要统计tcp连接每种状态的连接的数量 netstat -an | awk '/^tcp/ {++S[$NF]} END ...
  • Windows下建立TCP连接和终止TCP连接

    千次阅读 2016-09-13 13:10:18
    1.请仔细解释建立TCP连接的三个步骤。 答:三次握手 ⑴ 请求端发送一个SYN报文段指明客户打算连接的服务器端口号,以及初始化、序号,SYN请求发送后,客户进入SYN_SENT状态。 ⑵ 服务器启动后首先进入LISTEN状态,当...
  • Tcp 连接出现大量 ESTABLISHED 连接

    万次阅读 2015-12-14 16:31:53
    在不考虑系统负载、CPU、内存等情况下,netstat监控大量ESTABLISHED连接与Time_Wait连接。 # netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}' CLOSE_WAIT 348 ESTABLISHED 1240 TIME_WAIT ...
  • TCP连接复用

    千次阅读 2016-06-03 09:15:47
    这种技术能够大大减小服务器的性能负载,减少与服务器之间新建TCP连接所带来的延时,并最大限度的降低客户端对后端服务器的并发连接数请求,减少服务器的资源占用。  一般情况下,客户端在发送HTTP请求之前需要先...
  • TCP连接后保持连接

    千次阅读 2016-05-17 13:35:23
    TCP连接当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次握手的,而释放则需要4次...
  • 在tcp应用中,server事先在某个固定端口监听,client主动发起连接,经过三路握手后建立tcp连接。那么对单机,其最大并发tcp连接数是多少?   如何标识一个TCP连接 在确定最大连接数之前,先来看看系统如何...
  • TCP连接的建立

    千次阅读 2018-01-16 15:37:18
    前言:TCP的问题已然困惑我很久了,一直是一知半解,靠记忆来记住TCP连接的过程,不能根本上理解,漏洞百出,最近抽时间把TCP经典书籍——《 TCP-IP详解》阅读了一下。废话不多说,这篇博客的目的是希望能帮助刚...
  • TCP连接和释放

    千次阅读 2017-03-05 22:03:03
    一、TCP连接过程 1、TCP连接状态图 TCP的三次连接中,客户端是主动链接,服务器是被动连接,整个过程有三次数据报文段的传送,所以TCP建立过程又称为三次握手。 服务器进程先创建传输控制块TCB,准备接受接受...
  • TCP连接异常处理

    千次阅读 2018-12-07 13:40:47
    Netty使用TCP连接错误 欢迎关注驿外残香 | HC的博客 表面原因 在与嵌入式组进行TCP连接时发生未知错误导致服务器接收不到数据。并且Netty封装的exceptionCaught方法以及channelInactive方法捕获不到任何的报错...
  • TCP连接和释放过程

    千次阅读 2019-04-03 15:59:06
    一、TCP连接 TCP建立连接的过程叫做握手,握手需要在客户端和服务器之间交换三个TCP报文段来完成,这就是TCP三次握手。 1.A主机向B发送连接请求报文段,这是首部中的同部位SYN=1,同时选择一个初始序号seq=x,...
  • 使用netstat查看tcp连接、udp连接

    千次阅读 2019-09-17 11:42:09
    [root@dbserver ~]# netstat -nt --->>...查看tcp连接,注意看第二列和第三列 Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp ...
  • 单机最大tcp连接

    万次阅读 2016-09-01 15:13:24
    单机最大tcp连接数 网络编程 在tcp应用中,server事先在某个固定端口监听,client主动发起连接,经过三路握手后建立tcp连接。那么对单机,其最大并发tcp连接数是多少? 如何标识一个TCP连接 在确定最大连接数...
  • tcp连接中,有两种连接攻击方式,是半连接攻击机和全连接攻击,对此搜积相关资料做了一个总结。 &lt;1&gt;半连接攻击?  半连接攻击是一种攻击协议栈的攻击方式,坦白说就是攻击主机的一种攻击方式。...
  • TCP 连接状态详解

    千次阅读 多人点赞 2017-03-31 23:39:48
     一个TCP连接的过程中,会经历一系列的状态变化,这些变化包括: LISTEN,SYN_SENT,SYN-RECEIVED,ESTABLISHED,FIN-WAIT-1,FIN-...其中CLOSED是一个虚构的状态,因为CLOSED的TCP连接的TCB(Transmission
  • 检测TCP连接是否在线

    千次阅读 2017-11-06 17:40:07
    TCP连接、心跳
  • linux获取TCP连接

    千次阅读 2018-06-23 08:50:02
    linux获取TCP连接
  • 理论上有多少tcp连接

    千次阅读 2018-07-05 19:31:34
    如何标识一个TCP连接在确定最大连接数之前,先来看看系统如何标识一个tcp连接。系统用一个4四元组来唯一标识一个TCP连接:{local ip, local port,remote ip,remote port}。 client最大tcp连接数client每次发起tcp...
  • 各种查看TCP连接的命令

    千次阅读 2019-02-27 19:44:27
    TCP连接统计查看当前各种TCP连接状态netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 查看80端口连接数netstat -tan | grep "ESTABLISHED" | grep ":80" | wc -l 查看TCP连接状态netstat -...
  • TCP连接、Http连接与Socket连接

    千次阅读 2013-09-25 17:28:09
    1、TCP连接 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。 建立起一个TCP连接...
  • TCP连接异常终止分析

    千次阅读 2017-04-11 18:57:21
    CP的异常终止是相对于正常释放TCP连接的过程而言的,我们都知道,TCP连接的建立是通过三次握手完成的,而TCP正常释放连接是通过四次挥手来完成,但是有些情况下,TCP在交互的过程中会出现一些意想不到的情况,导致...
  • TCP连接占用的资源

    千次阅读 2018-12-08 14:55:04
    维持一个tcp连接需要占用哪些资源,下面就总结一下最近学习的内容,不足之处,请读者多多指正。 一个tcp连接需要:1,socket文件描述符;2,IP地址;3,端口;4,内存 TCP连接的四元组:源IP 源端口 目...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 105,292
精华内容 42,116
关键字:

tcp连接