0%

[计网]socket缓冲区

一. 简介#

每个socket被创建后,无论使用的是TCP协议还是UDP协议,都会创建自己的接收缓冲区和发送缓冲区。当我们调用write()/send() 向网络发送数据时,系统并不会 马上向网络传输数据,而是首先将数据拷贝到发送缓冲区,由系统负责择时发送数据。根据我们选用的网络协议以及阻塞模式,系统会有不同的处理。

这些socket缓冲区特性可整理如下:

  • socket缓冲区在每个套接字中单独存在;
  • socket缓冲区在创建套接字时自动生成;
  • 即使关闭套接字也会继续传送发送缓冲区中遗留的数据;
  • 关闭套接字将丢失接收缓冲区中的数据。

二. blocking(默认)和nonblock模式下read/write行为的区别:#

将socket fd设置为nonblock(非阻塞)是在服务器编程中常见的做法,采用blocking IO并为每一个client创建一个线程的模式开销巨大且可扩展性不佳(带来大量的切换开销),更为通用的做法是采用线程池+Nonblock I/O+Multiplexing(select/poll,以及Linux上特有的epoll)。

1
2
3
4
5
6
7
8
// 设置一个文件描述符为nonblock
int set_nonblocking(int fd)
{
int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
flags = 0;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

- read/recv(有数据时立即返回) write/send
blocking receive buffer为空时等待 在缓冲区足以放下整个buffer时才返回
non-blocking 当receive buffer为空时, 立即返回-1(errno = EAGAIN或EWOULDBLOCK) 返回能够放下的字节数,之后调用则返回-1(errno = EAGAIN或EWOULDBLOCK)

三. 问题思考#

问题1#

Client 创建一个 TCP 的 socket,并通过 SO_SNDBUF 选项设置它的发送缓冲区大小为 4096 字节,连接到 Server 后,每 1 秒发送一个 TCP 数据段长度为 1024 的报文。Server 端不调用 recv(), 会发生什么?

  • Phase 1: Server 端的 socket 接收缓冲区未满,所以尽管 Server 不会 recv(),但依然能对 Client 发出的报文回复 ACK;
  • Phase 2: Server 端的 socket 接收缓冲区被填满了,向 Client 端通告零窗口(Zero Window)。Client 端待发送的数据开始累积在 socket 的发送缓冲区;
  • Phase 3: Client 端的 socket 的发送缓冲区满了,用户进程阻塞在 send() 上。

问题2#

write返回大于0时, 这部分数据是否发送成功? - 不一定, write返回大于0仅表示写到了socket发送缓冲区成功, 若此时网络异常tcp断开了或者对方close了fd, 发送失败。 - 因此write成功无法说明对方已经收到数据。可以用应用程序级的ACK来解决这个问题

四. netstat查看socket#

查看linux socket发送缓冲区大于1的socket#

netstat -nt查看tcp端口, 发送缓冲区大于0的连接

1
2
3
4
5
6
7
$ netstat -nt|awk '{if($3>=1)print $0}'
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 1 xxx.xxx.xxx.29:51064 xxx.xxx.xxx:8999 SYN_SENT
tcp 0 1 xxx.xxx.xxx.29:51981 xxx.xxx.xxx:8999 SYN_SENT
tcp 0 112 xxx.xxx.xxx.29:32200 xxx.xxx.xxx:58208 ESTABLISHED
tcp 0 1 xxx.xxx.xxx.29:50507 xxx.xxx.xxx:443 SYN_SENT
各字段说明
1
2
3
4
5
- Recv-Q: 接受缓冲区待处理数据 The count of bytes not copied by the user program connected to this socket.
- Send-Q: 发送缓冲区待处理数据 The count of bytes not acknowledged by the remote host.
- Address: 本地端口 Address and port number of the local end of the socket
- Foreign Address: 远端端口 Address and port number of the remote end of the socket.
- State: 连接状态

reference#

  1. 一个 TCP 发送缓冲区问题的解析
  2. 查看并修改socket接收和发送缓冲区大小
  3. 深刻理解socket编程中的read&&write
  4. 谈谈socket缓冲区
  5. TCP Sliding Window Acknowledgment System For Data Transport, Reliability and Flow Control
  6. TCP Sliding Window
  7. 滑动窗口,TCP的流量控制机制