Linux-Socket编程-TCP阻塞方式05


写一对TCP Socket 的测试程序,分为client 和server,分别运行在不同虚拟机上

  • 测试程序tcp_server5-1,接受client 的连接成功后,用一句getchar()进入等待输入状态

  • 测试程序tcp_client5-1,连接服务端成功后,用write 函数不断向服务端写入数据(加计数 器统计写入了多少字节),大约写入多少字节后会使write 函数不再返回(阻塞状态)

    第一次阻塞

    阻塞解除

    再次阻塞后解除

  • server 端在getchar()后用read 进行读(假设每次读n 个字节),读入多少字节后,client 端的write 函数可以返回?这说明了什么问题?

    socket缓冲区

    每个 socket 创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。

    write()/send() 并不会立刻向网络中传输数据,而是先将数据写入缓冲区,再由TCP协议将数据从缓冲区发送到目标机器。一旦数据写入到缓冲区,函数就可以成功返回。不管它们有没有到达 目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。

    read()/recv() 函数也是如此,从输入缓冲区中读取数据,而不是直接从网络中读取。

    socket阻塞模式

    对于TCP套接字,默认情况下是属于阻塞模式,当使用 write() / send() 发送数据时:

    1. 首先会检查缓冲区,如果缓冲区的可用空间长度 小于 要发送的数据,那么 write() / send() 会被阻塞,直到缓冲区中的数据被发送到目标机器,腾出足够的空间,才唤醒 write() / send() 函数 继续写入数据。

    2. 如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入, write() / send() 会被阻塞,直到数据发送完毕缓冲区解锁, write() / send() 才会被唤醒。

    3. 如果要写入的数据大于缓冲区的最大长度,那么将分批写入,直到所有数据都写入缓冲区 write() / send() 才能返回。

    当使用 read() / recv() 读取数据时:

    1. 首选检查输入缓冲区,如果缓冲区中有数据,那么就读取,否则函数会阻塞,直到网络有数据的到来。

    2. 如果要读取的数据长度 小于 缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将吧不断积压,直到下次 read() / recv() 函数再次读取。

    3. read() / recv() 调用,一定要等到读取到数据才会返回,否则就一直被阻塞。

  • 在整个过程中用新会话打开终端后,用netstat 命令观察tcp 连接的各种信息(netstat 可以带哪些参数?显示的内容代表什么?)

    netstat命令用来打印Linux中网络系统的状态信息,可让你得知整个Linux系统的网络情况。

    netstat命令输出说明:

    Proto
       套接字使用的协议。
    Recv-Q
       连接此套接字的用户程序未拷贝的字节数。
    Send-Q
       远程主机未确认的字节数。
    Local Address
       套接字的本地地址(本地主机名)和端口号。除非给定-n选项,否则套接字地址
       按标准主机名(FQDN)进行解析,而端口号则转换到相应的服务名。
    Foreign Address
       套接字的远程地址(远程主机名)和端口号。
       套接字的状态。因为在RAW协议中没有状态,而且UDP也不用状态信息,所以此行留空。
       通常它为以下几个值之一:
       ESTABLISHED
              套接字有一个有效连接。
       SYN_SENT
              套接字尝试建立一个连接。
       SYN_RECV
              从网络上收到一个连接请求。
       FIN_WAIT1
              套接字已关闭,连接正在断开。
       FIN_WAIT2
              连接已关闭,套接字等待远程方中止。
       TIME_WAIT
              在关闭之后,套接字等待处理仍然在网络中的分组
       CLOSED 套接字未用。
       CLOSE_WAIT
              远程方已关闭,等待套接字关闭。
       LAST_ACK
              远程方中止,套接字已关闭。等待确认。
       LISTEN 套接字监听进来的连接。如果不设置 (-l)或者(-a)
              选项,将不显示出来这些连接。
       CLOSING
              套接字都已关闭,而还未把所有数据发出。
       UNKNOWN
              套接字状态未知
    User
       套接字属主的名称或UID。
    PID/Program name
       以斜线分隔的处理套接字程序的PID及进程名
    
  • 测试程序tcp_server5-2/tcp_client_5-2,双方角色互换,即server 写至阻塞为止,然后 client 开始读,直到server 端解除阻塞,观察整个过程

    第一次阻塞

    阻塞解除

    再次阻塞后解除

  • 测试程序tcp_server5-3/tcp_client_5-3,功能同5-1,在其中通过设置函数改变TCP 收发 缓冲区大小,通过netstat 观察整个过程

    第一次阻塞

    阻塞解除

    再次阻塞后解除

参考: socket缓冲区以及阻塞模式 netstat命令