Linux C/C++网络编程实战-陈硕-笔记15-如何正确使用 TCP

netcat

在这里插入图片描述

  • netcat 除了读取 socket 描述符,还要读取 stdin 和 stdout
  • 并发模型
    • thread-per-connection
    • IO 复用和非阻塞 IO 配合
  • 如何安全的关闭 TCP 连接
  • 为什么 IO复用 必须和非阻塞 IO 一起使用

netcat 基本功能

  • 信号发生器:发送数据。nc > /dev/zero、类似chargen服务
  • 负载:接收数据。nc > /dev/null、类似discard服务
  • 通过dd产生定量数据,通过nc发送测试网络带宽,dd /dev/zero | nc、类似ttcp服务
  • 两台机器之间通过nc拷贝文件,nc < file, nc > file、类似scp服务

    关于使用 nc 传输文件,示例如下:
    在这里插入图片描述
    注意:

    1. 在使用nc传输文件后,校验一下文件的完整性,例如使用md5校验。
    2. netcat 版本不同,某些特性可能会存在差异。例如,该版本nc以EOF为断开连接的标志,而其他版本的nc可能需要识别Ctrl-C信号才断开连接(如果是这样的话,请试一下参数-q0 参数 或 -N 参数)。

在这里插入图片描述

如何正确关闭一个 TCP 连接

在这里插入图片描述

send()/write() 成功返回只意味着内核接收了数据,并准备在某些时候发送它们。内核接收数据后,还要把数据包发送到网卡,并在网络中各个网卡遍历,最终到达远程主机。远程主机的内核确认到数据,拥有该 socket 的进程从中读取数据,此时数据才真正到达应用程序。

也就是说,当最后一次 send 函数执行完之后,并不意味着对方已经接收到完整的数据了,如果此时我们需要关闭连接,应再确认一下对方是否已经将数据接收完毕。如果贸然的使用 close 关闭连接,可能会使得数据接收不完整。

代码
  • 链接:https://github.com/Anita-Mul/recipes/blob/master/tpc/bin/sender.cc
  • sender
    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();
      while ( (nr = stream->receiveSome(buf, sizeof buf)) > 0)
      {
        // do nothing
      }
      printf("All done.\n");
    
      // TcpStream destructs here, close the TCP socket.
    }
    
  • 其中 21 ~ 26 行是安全关闭套接字的方法。如果我们将这几行代码注释,模拟不安全的关闭套接字程序,然后进行测试,就有可能测出数据丢失的情况。
示例1:
  • 在服务器上开启 sender 服务,发送一个 1k 大小的文件【正常的接收】
    在这里插入图片描述
  • 在客户端,使用 nc 连接服务端,接收文件
    在这里插入图片描述
示例2
  • 模拟数据未读取完,服务端发送的数据为 1M bytes
    在这里插入图片描述
  • 如果我们在客户端等待时,输入一些数据,可以模拟tcp发送数据不完整的情况。 (客户端nc 有用户输入的数据,发送到服务端后 sender 没有读取,使得 sender 在close() 的时候,没有进行 FIN 分解,而是进行了 RST 分解 直接断开了连接。)
    在这里插入图片描述
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值