|  | 级别: 初级 IBM,
2002 年 8 月 01 日 IBM eServer 开发者园地是关于 IBM eServer 硬件及相关软件开发人员的内容和参考资料的不断增长的集合。IBM eServer 开发者园地专注于提供 iSeries、pSeries、xSeries 和 zSeries 的开发人员内容,包括文章、样本代码、教程、如何做、工具、新闻、案例学习和论坛 — 实际上是开发人员想要和需要的有助于完成其工作的任何内容。
当从 MailStone 负载生成机器运行针对 Sendmail 群集的繁重负载时,我们发现并非所有客户机 smtp 连接都会在测试结束时关闭。netstat 报告了这些套接字仍然处于连接状态。在服务器端根本就没有相应的套接字(CLOSE_WAIT 中根本就没有)。tcp 中不应该发生这种情况。
我们发现某些在客户机上建立的套接字连接从来也没有在服务器上进入已建立状态。服务器将暂时将该连接报告为 SYN_RCVD,然后该项会从该连接的服务器端消失(请参阅图 1)。发起建立该连接的客户机进程的系统调用跟踪会报告已建立套接字的进程轮询,但因为服务器上没有建立连接,所以不会显示任何内容。
图 1,建立 TCP 连接的状态图
我们使用 tcpdump 捕获了针对一台服务器的测试。我们发现所有的包(客户机的 SYN、服务器的 SYN 和 ACK 以及最终客户机的 ACK )都显示到达了服务器的以太网接口。客户机向服务器发送了建立 tcp 连接所需要的全部包,但服务器从未达到已建立状态。
我们还通过检查 netstat -s 统计信息注意到:ListenOverFlows 的计数增量和测试最终挂起的客户机数量相同。按照 Linux C 调用侦听(listen)的手册页,listen 函数获取两个参数,套接字(s)和 backlog。并且它声明 backlog 是正在等待被接受的已完全建立的套接字的最大数量。可是,如果连接到达了,但接受队列却已经达到了 backlog 值,那样会发生什么情况呢?内核会略过在服务器上建立新套接字的过程。请参阅 2.4 Linux 内核的 net/ipv4/tcp_ipv4.c 中的“tcp_v4_syn_recv_sock”函数。
我们还发现,缺省情况下,ftp.kernel.org 的 2.4.4 内核将 /proc/sys/net/ipv4/tcp_abort_on_overflow 的值设置为 0。因此,当您遇到上述的溢出事件时,服务器就不再建立套接字,而且也不会向客户机发送 tcp 复位信息。它只是简单地将套接字抛下不管,然后依靠客户机超时和再次尝试来处理。对于某些协议和客户机,这是有效的,但对其它客户机就明显无效。将 /proc/sys/net/ipv4/tcp_abort_on_overflow 值设置为 1 会使内核在接受 backlog 溢出时发送复位信息。
可以在运行时在 sendmail.cf 文件中配置侦听 C 调用的 backlog 参数。该选项是 DaemonPortOptions 加等号,加一列用逗号分隔的键,再加等号,加一个值对。因此您可以设置成 DaemonPortOptions=listen=512 或更高。这可能有助于应付激增的流量。但是,在我们的测试示例中,在几分钟内会持续有几十个连接。因此,实际上无论将 backlog 设置成什么,都会很快达到其上限。其观点是如果客户机发起建立连接的速度比服务器处理它们的速度快,那么接受队列就会持续增长。如果这个模式继续下去,时间一长,无论接受队列有多长,都会被填满并溢出。
支持文档
来自 Linux 2.4.4 内核 net/ipv4/tcp_ipv4.c
/*
* The three way handshake has completed - we got a valid synack -
* now create the new socket.
*/
struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
struct open_request *req,
struct dst_entry *dst)
{
struct tcp_opt *newtp;
struct sock *newsk;
if (tcp_acceptq_is_full(sk))
goto exit_overflow;
. . .
通常这是实际创建新套接字的地方
. . .
exit_overflow:
NET_INC_STATS_BH(ListenOverflows);
exit:
NET_INC_STATS_BH(ListenDrops);
dst_release(dst);
return NULL;
}
|
来自 listen.2 手册页
名称
listen — 侦听套接字上的连接
摘要
#include <sys/socket.h>
int listen(int s, int backlog);
描述
为了接受连接,首先用 socket(2) 创建一个套接字,用 listen 表示愿意接受入站连接并指定入站连接的队列限制,
然后用 accept(2) 接受连接。listen 调用仅适用于 SOCK_STREAM 或 SOCK_SEQPACKET 类型的套接字。
backlog 参数定义了连接被挂起的队列的最大可能长度。如果连接请求到达时队列已满,则客户机可能会收到带有
ECONNREFUSED 指示的出错信息,或者,如果底层协议支持重新传送,则可以忽略该请求以便重试得以进行。
|
关于作者  | |  | IBM has authored this article |
对本文的评价
|  | IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。 |