美文网首页
Socket和TCP的对应关系

Socket和TCP的对应关系

作者: 喻家山车神 | 来源:发表于2019-02-28 21:07 被阅读0次

    前言

      使用TCP/IP网络协议时,一般都是基于Socket的API进行网络编程。应用程序通过Socket接口和内核交互,内核维护TCP/IP协议的具体通信过程。那么Socket的API具体是如何和TCP/IP协议栈对应呢?

    连接

      建立连接相关的API有connect,listen,accept。服务端使用listen,accept等待连接,客户端使用connect进行连接。
      当服务端调用listen后,会向系统内核注册Syn队列和Accept队列,接下来调用accept后会监听Accept队列。此时如果客户端调用connect向服务端发出连接请求,就会发生传说中大名鼎鼎的三次握手过程。

    1. 客户端内核向服务端内核发出SYN网络包;
    2. 服务端内核在Syn队列插入一个节点,并且向客户端内核发送SYN+ACK网络包;
    3. 客户端内核发送ACK网络包,此时客户端的connect调用结束并返回,服务端内核如果收到这个ACK网络包,会从Syn队列中删除节点并在Accept队列中增加节点,此时服务端的accept调用就会监听到Accept队列的节点,并且返回。

      断开连接的API主要就是close方法。当任意一方调用close方法时,就会发生传说中的四次挥手过程。当一方调用close时,对方就会产生一个读事件,当读到的数据是0时,就知道对方关闭了连接。

    1. 主动关闭方发送FIN包,然后进入FIN_WAIT_1状态;
    2. 被动方收到FIN包以后,发送确认的ACK包,进入CLOSE_WAIT状态,主动断开方状态变成FIN_WAIT_2状态;
    3. 被动方发送FIN包表示本方断开连接,状态变成LAST_ACK状态;
    4. 主动关闭方接收到FIN包以后,发送ACK包确认,状态进入TIME_WAIT状态,被动关闭方变成CLOSED状态。

    发送和接收

      通信过程使用send和recv方法。发送数据时使用send方法,send会将应用需要发送的数据拷贝到内核的发送缓冲区;接受数据时使用recv方法,recv会从内核缓冲区拷贝数据到应用进行处理。
      在阻塞模式下调用send时,如果send的数量小于缓冲区的大小,会将应用数据拷贝到内核以后立即返回,如果send的数量大于缓冲区的大小,应用会等待内核将一部分数据发送成功清除缓冲区再拷贝,直到所有的数据都拷贝到内核以后才返回。
      在非阻塞模式下调用send时,无论发送的数据是否大于内核的缓冲区,都会立即返回,返回的是成功拷贝的数据的数量。
      无论什么情况,应用程序发送数据都只会将数据拷贝到内核的缓冲区,并不表示服务端成功接收了数据。
      在阻塞模式下调用recv时,如果内核缓冲区没有数据,会一直等待,直到读取到数据。
      在非阻塞模式下调用recv时,如果内核缓冲区没有数据,会立即返回。

    超时

    • 建立连接超时
        客户端应用在调用connect以后,内核在发送SYN以后,在指定的超时时间内没有收到服务端返回的ACK网络包。
    • 读数据超时
        客户端应用在调用recv以后,在指定的超时时间内没有收到服务端返回的数据。
    • 写数据超时
        客户端内核在发送外数据以后,由于网络问题或者其它原因,导致服务端以后没有返回确认信息,此时系统内核在重试多次以后关闭这个连接。此时如果客户端应用继续调用send写数据,就会产生异常。

    经典问题

    • 关闭连接
        如果CLOSE_WAIT状态大量堆积,说明被动关闭方忘记调用close,此时被动关闭方一直处于CLOSE_WAIT状态,久而久之服务器端的连接句柄就会被耗尽。当然客户端并不会一直处在FIN_WAIT_2状态,过一段时间以后,会自动跳到下一个状态。
        如果TIME_WAIT状态大量堆积,这种情况一般属于正常现象,主动关闭方在收到被动关闭方的close请求以后,会进入TIME_WAIT状态,并保持一定的时间。这是为了确保被动关闭方没有收到主动关闭方发出的ACK包,此时被动关闭方再次发送FIN时,在这段时间内主动关闭方可以再次返回ACK包确认。一般如果某台机器短时间发出了大量的短连接请求(比如HTTP请求),就会出现很多的TIME_WAIT状态。一般来说,如果出现大量的TIME_WAIT状态,服务器会配置成处于TIME_WAIT状态的可复用。

    • 为什么握手只需要三次,挥手却需要四次?
        客户端在和服务端建立连接时,服务端应答以后肯定也需要和客户端建立连接,所以可以把ACK和SYN包一起发送。但是断开连接时,被动断开的一方并不一定需要马上断开,可能还需要继续发送数据,所以此刻需要先发送ACK包确认收到主动断开连接方的FIN包,然后在需要的时候发送FIN包表示本方也要断开连接了。

    • RST包
        主动关闭方发出的ACK如果被动关闭方没有收到,被动关闭方再次发送FIN时,如果主动关闭方在TIME_WAIT状态下,会再次发送ACK包;否者就会发出一个RST包。
        服务器返回了“RST”时,如果此时客户端正在从Socket套接字的输出流中读数据则会提示Connection reset”;服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会提示“Connection reset by peer”。
        使用SO_LINGER时,主动关闭方可以直接关闭连接,避免关闭过程中的状态过度。

      以上内容都没有经过编码验证,也没有通过源码确认,纯粹百度和google搜索各种资料汇总

    相关文章

      网友评论

          本文标题:Socket和TCP的对应关系

          本文链接:https://www.haomeiwen.com/subject/ttqhuqtx.html