• 安全关闭Tcp连接


    close与shutdwon

    int close(int sockfd);
    

    关闭sokcet,这里注意:当程序调用close关闭socket的时候,如果缓冲区中仍然有数据的话,协议栈会发送RST包代替FIN包,丢弃缓冲的数据,强行关闭连接

    int shutdown(int sockfd, int howto);
    

    该函数的行为依赖howto参数的值:

    • SHUT_RD
      关闭读功能,套接字中不再有数据可接收,而且套接字接收缓冲区中的现有数据都被丢弃。

    • SHUT_WR
      关闭写功能,对于TCP套接字,称为半关闭(half-close)。当前在套接字发送缓冲区中的数据将被发送掉,后跟TCP的正常连接终止序列。

    • SHUT_RDWR
      关闭读写功能,等于调用shutdown函数两次,连接的读半部和写半部都关闭。

    代码参考

    recipes-master/tpc/sender.cc

    void sender(const char* filename, TcpStreamPtr stream)
    {
      FILE* fp = fopen(filename, "rb");
      if (!fp)
        return;
    
      printf("Sleeping 10 seconds.\n");
      sleep(10);
    
      printf("Start sending file %s\n", filename);
      char buf[8192];
      size_t nr = 0;
      while ( (nr = fread(buf, 1, sizeof buf, fp)) > 0)
      {
        stream->sendAll(buf, nr);
      }
      fclose(fp);
      printf("Finish sending file %s\n", filename);
    
      // Safe close connection
      printf("Shutdown write and read until EOF\n");
      stream->shutdownWrite();	// 相当于shutdown(sock,SHUT_WR)
      // 读出缓冲区数据直到为0
      while ( (nr = stream->receiveSome(buf, sizeof buf)) > 0)
      {
        // do nothing
      }
      printf("All done.\n");
    
      // TcpStream destructs here, close the TCP socket.
      // 析构函数会调用close关闭socket
    }
    

    Tcp连接错误关闭示例

    依旧采取上面sender.cc的程序,我们先把下面几行注释掉

    stream->shutdownWrite();	// 相当于shutdown(sock,SHUT_WR)
      // 读出缓冲区数据直到为0
      while ( (nr = stream->receiveSome(buf, sizeof buf)) > 0)
      {
        // do nothing
      }
    

    正常情况下,sender发送文件,nc正常接收

    [wang@localhost tpc]$ ./sender ttcp 12345
    Accepting... Ctrl-C to exit
    accepted no. 1 client
    Sleeping 10 seconds.
    Start sending file ttcp
    Finish sending file ttcp
    Shutdown write and read until EOF
    All done.
    
    [wang@localhost tpc]$ nc localhost 12345 | wc -c
    1236576
    

    随后,我们在nc起来的时候输入一些数据

    [wang@localhost tpc]$ nc localhost 12345 | wc -c
    42718472019840918490-1249-01284-01298-04912-03491-0391-03912-03912-0
    Ncat: Connection reset by peer.
    777764
    

    第一行是我们输入的数据,这些数据会发送给sender,最后一行是我们接收到的数据大小,很明显是比原来的要少的。这是因为sender本身并没有read操作,所以这些输入的数据会滞留在缓冲区,但是sender发送完数据,直接调用close,根据前面对close的介绍,这时候sender会发送一个RST,导致Tcp连接强行断开,所以nc并没有完全接受完数据。

    下面我们恢复sender.cc原来的代码,再测试一下

    [wang@localhost tpc]$ nc localhost 12345 | wc -c
    42718472019840918490-1249-01284-01298-04912-03491-0391-03912-03912-0
    1236576
    

    接收的数据回归正常。

    安全关闭TCP的流程

    • 发送方不再发送数据后,使用 shutdown(sock,SHUT_WR) 关闭本端套接字的输出流。shutdown() 会向对方发送 FIN 包。FIN 包通过四次挥手过程断开连接,可以有效的等待数据发送完成再断开连接。
    • 调用 read() 函数,read()将会返回0,代表对方也不再发送数据。此时连接已断开。
      (这里read()返回0应考虑客户端存在Bug或恶意的不返回0的情况,使得客户端永远不满足read()=0的情况。因此这里因考虑有超时机制,在shutdown之后若干秒内如果没有满足read()=0,则强制断开连接并有相应的错误处理)
    • 调用 close() 函数关闭套接字。
  • 相关阅读:
    tensorflow遇到的问题
    C语言-字符串与输入输出
    开源教育对话大模型 EduChat
    智慧灯杆网关智慧交通应用
    Linux下手动修改服务器时间(没网环境下)
    Win11怎么设置让CPU性能全开?Win11CPU怎么设置高性能模式?
    全球NPE知识产权风险及我国应对策略
    目的和目标的差异|丰田自动工程完结的目的、目标、应用化的意义和明确、二
    ControllerBeanNameHandlerMapping类功能简介说明
    mongodb
  • 原文地址:https://blog.csdn.net/weixin_45419466/article/details/138536407