什么时候出现RST

  • TCP 接收缓冲区中存在未处理的数据时关闭连接,会向对端发送RST报文。

下面进行实验验证。

//server
int main() 
{
    int sock_listen = socket(AF_INET, SOCK_STREAM, 0);
    int recv_size = 100000;
    socklen_t optlen = sizeof(recv_size);
    setsockopt(sock_listen, SOL_SOCKET, SO_RCVBUF, (void*)&recv_size, optlen);
    struct sockaddr_in addr_listen;
    bzero(&addr_listen, sizeof(addr_listen));
    addr_listen.sin_addr.s_addr = inet_addr("192.168.248.128");
    addr_listen.sin_port = htons(12345);
    addr_listen.sin_family = AF_INET;
    Bind(sock_listen, (struct sockaddr *) &addr_listen, sizeof(addr_listen));
    Listen(sock_listen, 20);
    int sock_conn;
    sock_conn = Accept(sock_listen, NULL, NULL);
    sleep(10);  //等待10秒,确保接收缓冲区已收到100000字节
    close(sock_conn);//不read,直接关闭
}
//==================================
//client
int main()
{
    int sock_clnt;
    struct sockaddr_in addr_serv;
    sock_clnt = socket(AF_INET, SOCK_STREAM, 0);
    memset(&addr_serv, 0, sizeof(addr_serv));
    addr_serv.sin_family = AF_INET;
    addr_serv.sin_port = htons(12345);
    addr_serv.sin_addr.s_addr = inet_addr("192.168.248.128");
    Connect(sock_clnt, (struct sockaddr*)&addr_serv, sizeof(addr_serv));
    char buf[100000] = {0};
    writen(sock_clnt, buf, sizeof(buf)); //发送100000字节
    while(1);
}

先后运行 server 和 client,使用 wireshark 抓包,结果如下:

直接看倒数第二项,server 回复的 ACK = 100001,说明 server 端的缓冲区已经接收了这 100000 字节,但由于没有读取(read)缓冲区就关闭(close)套接字,因此向 client 发出了 RST,即最后一项。

那么我们为 server 加上 read,读取这 100000 字节后再 close,结果如下:

这次就是标准的四次挥手啦!


  • 为了避免 FIN_WAIT1 状态的连接过多,我们可以调小 tcp_orphan_retries 的值,也可以通过 tcp_max_orphans 限制其数量, 如果孤儿连接数量大于它,新增的孤儿连接将不再走四次挥手,而是直接发送 RST 复位报文强制关闭。
  • 《UNP》P160——linger
  • close 后过段时间端口彻底关闭,收到 FIN也只会回复RST
文章作者: 极简
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 后端技术分享
Socket网络编程
喜欢就支持一下吧