【发布时间】:2020-05-03 14:30:55
【问题描述】:
我编写了基于 Berkeley 套接字的用户模式客户端-服务器 c 应用程序,该套接字通过某些专用网络进行交互。
情况肯定很奇怪。在某些模糊的情况下,连接有时会变得非常慢。在我的例子中,正常的 TCP 数据交换是每段大约 10-25 KB 的有效负载,但有时它会变成每段大约 200-500 字节。
经过一些故障排除后,我意识到其他网络服务无法重现此问题,因此看来是我的服务有问题。但我想不通,怎么了。它在 3.10 Linux 内核上运行良好,但在 4.4 上有这种奇怪的行为。会不会是一些内部内核更改导致了这样的问题?
我尝试使用 Linux sysctl 设置:
net.ipv4.tcp_congestion_control
net.ipv4.tcp_sack
net.ipv4.route.flush
但这并没有帮助。
似乎问题出现在监听套接字端。在 tcpdump 中,握手时 TCP 窗口大小正常。但是在第一个传入数据包窗口大小减小后(在侦听器方面)。
UPD
这是我的服务器端代码 sn-p:
serv_fd = socket(AF_INET, SOCK_STREAM, 0);
if (serv_fd == -1) {
perror("socket");
return;
}
server.sin_family = AF_INET;
server.sin_port = htons(LISTEN_PORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
#ifdef SET_BUF
if (setsockopt(serv_fd, SOL_SOCKET, SO_RCVBUF, &buflen, sizeof(int)) == -1) {
perror ("setsockopt");
return;
}
if (setsockopt(serv_fd, SOL_SOCKET, SO_SNDBUF, &buflen, sizeof(int)) == -1) {
perror ("setsockopt");
return;
}
#endif // SET_BUF
if (bind(serv_fd, (struct sockaddr *) &server, sizeof(server)) == -1) {
perror("bind");
return;
}
if (listen(serv_fd, 3)) {
perror("listen");
return;
}
printf("Server is listening on %u\n", LISTEN_PORT);
有人能解释一下我的问题吗?我将不胜感激!
它可能与最近的一些 Linux 内核修改有关吗?我是否需要调整一些 Linux 内核设置或检查一些用户模式设置(例如套接字选项或其他)?
附:问题不稳定。
更新:
tcpdump 的输出:
IP 10.0.0.34.31334 > 10.0.0.99.12345: Flags [S], seq 426261790, win 43690, options [mss 65495,sackOK,TS val 799180610 ecr 0,nop,wscale 7], length 0
IP 10.0.0.99.12345 > 10.0.0.34.31334: Flags [S.], seq 803872704, ack 426261791, win 65483, options [mss 65495,sackOK,TS val 799180567 ecr 799180610,nop,wscale 0], length 0
IP 10.0.0.34.31334 > 10.0.0.99.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 799180610 ecr 799180567], length 0
IP 10.0.0.34.31334 > 10.0.0.99.12345: Flags [P.], seq 1:1301, ack 1, win 342, options [nop,nop,TS val 799180610 ecr 799180567], length 1300
IP 10.0.0.34.31334 > 10.0.0.99.12345: Flags [P.], seq 1301:1804, ack 1, win 342, options [nop,nop,TS val 799181412 ecr 799180610], length 503
IP 10.0.0.99.12345 > 10.0.0.34.31334: Flags [.], ack 1804, win 512, options [nop,nop,TS val 799181412 ecr 799181412], length 0
10.0.0.34.31334 是客户端,10.0.0.99.12345 是服务器。注意最后一行意外的win 512。
UPD2: 我在 dmesg 中看到了几条关于 SYN-cookie 的消息,例如:
possible SYN flooding on port 12345. Sending cookies.
但它们与慢速传输的时间关系不大。
【问题讨论】:
-
很奇怪的情况。如果“问题不稳定”,你怎么能确定问题没有出现在 3.10 内核上。看看
dmesg输出。传输慢的时候有什么不寻常的地方吗? -
请注意,Cloudflare 博客条目 SYN packet handling in the wild 指出“在 4.3 之前的内核中,SYN 队列长度的计算方式不同。”我没有仔细看它,但我认为你的积压 3 在 4.3 之前被四舍五入到 16。这也表明将您的 backlog 增加到至少 16 可能会使您的性能类似于您在 3.10 中看到的性能。更改链接到博客here。
-
您还应该检查是否在 3.10 部署中启用了 SYN cookie。如果不是,SYN 将被丢弃,客户端将重新传输。 Here 是其他人在启用时间戳时观察到窗口大小和同步 cookie 的类似问题。 (如果您看不懂中文,请在 Chrome 中加载,右键单击并选择翻译,这会做得不错)。根据 cloudflare 博客,他们禁用了时间戳(这是存储 wscale 的位置),因此看不到这个问题。
-
@z0lupka 查看this change,它消除了
nr_table_entries,它曾经具有最小值8+1,向上取整为2 的幂=16。我实际上并没有尝试从listen()遵循backlog的值。要真正证明基于backlog值为 3 的 SYN 队列长度是16需要更多调查。 -
@z0lupka 有人通过here 完成了这项工作
标签: c c sockets tcp linux-kernel network-programming