Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192580
  • 博文数量: 30
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 476
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-07 18:15
个人简介

程序员一个。14年毕业。

文章分类

全部博文(30)

文章存档

2014年(13)

2013年(17)

我的朋友

分类: LINUX

2014-09-26 09:43:41

今天碰到一个奇葩的问题,一直跑的好好的程序,碰到某个服务器就不行了。

当前流程:
client                      server
SYN ------------------->
<------------------------SYN ACK
data with ack bit------>

客户端发送data后服务器一直没回ack,导致客户端重传data with ack。
显然,如果是服务器用户态丢包,那么必然四层协议栈肯定会回ack,然后因为用户态无法处理data,紧接着发送fin或者rst。所以基本可以定位是服务器四层丢包,或者服务器死机了,呵呵。
于是改动了自己的程序,让其ack后再发data,果不其然,通了,又呵呵。

查看了一下linux源码,基本确定服务器不是用的linux。
 
1:Linux作为服务器
在linux 2.6的实现中,当自己处于SYN_RECV状态下,收到带有ack的报文, 处理流程如下
tcp_rcv_state_process 函数:
if (th->ack)
{
case TCP_SYN_RECV:
.......
tcp_set_state(sk, TCP_ESTABLISHED);
 
switch (sk->sk_state)
{
case TCP_ESTABLISHED:
      tcp_data_queue(sk, skb);
}
 
即linux作为服务器端,在tcp三次握手时,允许客户端发送的ack带有数据,并且会处理数据。ack和数据是分开处理的。
 
2:Linux作为客户端
在linux 2.6的实现中,当自己处于SYN_SENT状态的时候,收到服务器端发送的syn ack时,处理流程如下:
tcp_rcv_synsent_state_process 函数:
............................
/*满足某些条件则不立刻发ack,而是和下次数据一起发ack*/
if (sk->sk_write_pending ||
    icsk->icsk_accept_queue.rskq_defer_accept ||
    icsk->icsk_ack.pingpong) {
/* Save one ACK. Data will be ready after
* several ticks, if write_pending is set.
*
* It may be deleted, but with this feature tcpdumps
* look so _wonderfully_ clever, that I was not able
* to stand against the temptation 8)     --ANK
*/
inet_csk_schedule_ack(sk);
icsk->icsk_ack.lrcvtime = tcp_time_stamp;
icsk->icsk_ack.ato = TCP_ATO_MIN;
tcp_incr_quickack(sk);
tcp_enter_quickack_mode(sk);
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
  TCP_DELACK_MAX, TCP_RTO_MAX);
 
discard:
    __kfree_skb(skb);
    return 0;
}
else
{
    tcp_send_ack(sk);
}
..................
 
即linux作为客户端,在tcp三次握手时,允许自己发送的ack带有数据。


呵呵呵。

紧接着查看rfc 793

If the state is SYN-SENT then

 

      first check the ACK bit

 

        If the ACK bit is set

 

          If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless

          the RST bit is set, if so drop the segment and return)

 

            

 

          and discard the segment.  Return.

 

          If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable.

 

      second check the RST bit

 

[Page 66]                                                               

 

September 1981                                                          

                                           Transmission Control Protocol

                                                Functional Specification

SEGMENT ARRIVES

 

        If the RST bit is set

 

          If the ACK was acceptable then signal the user "error:

          connection reset", drop the segment, enter CLOSED state,

          delete TCB, and return.  Otherwise (no ACK) drop the segment

          and return.

 

      third check the security and precedence

 

        If the security/compartment in the segment does not exactly

        match the security/compartment in the TCB, send a reset

 

          If there is an ACK

 

            

 

          Otherwise

 

            

 

        If there is an ACK

 

          The precedence in the segment must match the precedence in the

          TCB, if not, send a reset

 

            

 

        If there is no ACK

 

          If the precedence in the segment is higher than the precedence

          in the TCB then if allowed by the user and the system raise

          the precedence in the TCB to that in the segment, if not

          allowed to raise the prec then send a reset.

 

            

 

          If the precedence in the segment is lower than the precedence

          in the TCB continue.

 

        If a reset was sent, discard the segment and return.

 

      fourth check the SYN bit

 

        This step should be reached only if the ACK is ok, or there is

        no ACK, and it the segment did not contain a RST.

 

        If the SYN bit is on and the security/compartment and precedence

 

                                                               [Page 67]

 

                                                          September 1981

Transmission Control Protocol

Functional Specification

                                                         SEGMENT ARRIVES

 

        are acceptable then, RCV.NXT is set to SEG.SEQ+1, IRS is set to

        SEG.SEQ.  SND.UNA should be advanced to equal SEG.ACK (if there

        is an ACK), and any segments on the retransmission queue which

        are thereby acknowledged should be removed.

 

        If SND.UNA > ISS (our SYN has been ACKed), change the connection

        state to ESTABLISHED, form an ACK segment

 

          

 

        and send it.  Data or controls which were queued for

        transmission may be included.  If there are other controls or

        text in the segment then continue processing at the sixth step

        below where the URG bit is checked, otherwise return.

 

        Otherwise enter SYN-RECEIVED, form a SYN,ACK segment

 

          

 

        and send it.  If there are other controls or text in the

        segment, queue them for processing after the ESTABLISHED state

        has been reached, return.

 

      fifth, if neither of the SYN or RST bits is set then drop the

      segment and return.



呵呵呵呵呵呵。

阅读(4227) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~