- 论坛徽章:
- 0
|
的 ddd原帖由 flw 于 2008-9-2 18:25 发表
奇怪啊,为什么服务端是 SYN_RECV,客户端却是 ESTABLISHED 呢?
linux 2.6.26.3的结果如下,2.6.11貌似是一样的,估计版本之间没什么差别
这是linux判断是否超出backlog的方法
比如backlog 是5,那么真时的连接允许保持6条,sk_ack_backlog = 0为默认值
再第7次连接时才返回真(第一次为0,..第6次为5,5==5)
static inline int sk_acceptq_is_full(struct sock *sk)
{
return sk->sk_ack_backlog > sk->sk_max_ack_backlog;
}
对于别的backlog类似,这可能是为了处理backlog == 0的情况(unp说对于0的解释不同实现不同,这就是linux的解释,至少允许1个连接)
为了说明情况我以backlog为1为例子,为5也一样,但是省的改flw给的c代码
当第一个connect来时,ok连接成功,sk_ack_backlog(0) > sk_max_ack_backlog(1) 不成立
第2个连接时,连接一样成功 sk_ack_backlog(1) > sk_max_ack_backlog(1) 不成立
到第3个时,full了,这个条件的判断是在收到connect发出3次握手中的第3个包,即ack包时检查的
代码如下
listen_overflow:
printk("%s %d: overflow\n", __func__, __LINE__);
if (!sysctl_tcp_abort_on_overflow) {
inet_rsk(req)->acked = 1;
return NULL;
}
embryonic_reset:
printk("%s %d: reset\n", __func__, __LINE__);
NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS);
if (!(flg & TCP_FLAG_RST))
req->rsk_ops->send_reset(sk, skb);
inet_csk_reqsk_queue_drop(sk, req, prev);
return NULL;
|
printk是我加的
代码我没有继续跟踪,但是很明显:
如果sysctl_tcp_abort_on_overflow为0 (默认值/proc/sys/net/ipv4/tcp_abort_on_overflow)是,那么只是是丢弃最后的ack包(当然客户端不会知道,这也是flw说的客户认为连接的原因,客户ack出去就连接完成了),后果和服务器没收到ack包是一样的,如果客户这个时候直接read,write,服务器可想而知,会重传syn-ack包,因为它“没收到”ack(即它还在等ack),事实是,即使客户不操作,服务器也会重发syn-ack,原因很简单,3次握手要完成
如果sysctl_tcp_abort_on_overflow不为0,那么直接rst了,当然connect不会知道,基于同样的理由,connect已经返回了,读写时就会知道被reset这个事实了
这些我想都是可以完全试验的,但是看代码以及printk,加上抓包,已经很明显了 |
|