您当前的位置: 首页 >  linux

phymat.nico

暂无认证

  • 0浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

TCP三次握手在linux内核中的实现

phymat.nico 发布时间:2017-12-26 00:04:38 ,浏览量:0

TCP三次握手在linux内核中的实现

 

以下基于linux内核2.4.0源码(转自www.yuanma.org/)

    以前一直使用的网络通讯的函数都是工作在阻塞模式。在看connect实现源码时,突然想到tcp/ip的 三次握手在内核如何实现的,尤其是在非阻塞模式下式,涉及到等待对端回送ack包,而本端又要立即返 回,想来这种实现肯定是遵循某种规则或是将所有的相关函数组合起来。     查看一些网络通信书籍,可知果然如此。应用编程如果设置为非阻塞模式,则连接时,connect发送 SYN包后立即返回-EINPROGRESS,表示操作正在处理中;随后应用可以在connect返回后做一些其它的处理, 最后在select函数中来捕获socket的连接、读写、异常事件以触发相关操作,下面我们看看内核中的相关 实现: 一、tcp/ip连接的三次握手过程:       client    SYN包--->      server       client          server 二、客户端支持      client发送2个包,一个SYN包,一个对服务器的响应ACK包。            client函数调用链:connect-->sys_connect->inet_stream_connect->tcp_connect...      看inet_stream_connect中实现的部分代码段:      ...      switch (sock->state) {      ...                         /*此处调用tcp_connect函数发送SYN包*/        err = sk->prot->connect(sk, uaddr, addr_len);          if (err < 0)  //出错则退出    goto out;        sock->state = SS_CONNECTING;

  /* 此处仅设置socket的状态为SS_CONNECTING表示连接状态正在处理;    * 不同之处在于非阻塞情况下,返回值设置为-EINPROGRESS表示操作正在处理    * 而阻塞式情况则在获得ACK包后将返回值置为-EALREADY.    */   err = -EINPROGRESS;   break;       }             timeo = sock_sndtimeo(sk, flags&O_NONBLOCK); //注意,如果此时设置了非阻塞选项,则timeo返回0         //如果socket对应的sock状态是SYN包已发送或收到SYN包并发送了ACK包,并等待对端发送第三此的ACK包  if ((1state = SS_CONNECTED;  err = 0;      out:  release_sock(sk);  return err;  ...     上面的描述有一个问题:对服务器的响应ACK包是什么时候发送的?对于非阻塞模式,应该是应用处理过程中 的某个异步时间;对于阻塞模式,则是在inet_wait_for_connect函数中睡眠时处理。     即网卡在收到对方的ack包后,上传给对应的socket时发送服务器的响应ACK包     函数调用链为:netif_rx-->net_rx_action-->...(IP层处理)-->tcp_v4_rcv-->tcp_v4_do_rcv-->       tcp_rcv_state_process-->tcp_rcv_synsent_state_process-->tcp_send_synack-->tcp_transmit_skb...     发送SYN包后,socket对应的sock的状态变成TCPF_SYN_SENT,网卡收到服务器的ack传到tcp层时,根据TCPF_SYN_SENT     状态,做相关判断后再发送用于第三次握手的ack包。至此,将socket的状态改为连接建立,即TCP_ESTABLISHED。     具体的代码大家可以根据我提供的函数调用链查看。     注意,以TCPF_前缀开头的状态都表示是中间状态,而已TCP_为前缀的状态才是socket的一个相对稳定的状态。              这里有一个疑问,,根据接收处理源码,先前的SYN包应该发送给服务器的监听socket,而第三次握手似乎应该发送给     连接(未真正连接,因为三次握手还没完成呢)的socket,这个问题有待进一步确认

三、服务器端支持     服务器端此时必须是监听状态,则其函数调用链为:           netif_rx-->net_rx_action-->...(IP层处理)-->tcp_v4_rcv-->tcp_v4_do_rcv-->           tcp_rcv_state_process-->tcp_v4_conn_request-->tcp_v4_send_synack...     在tcp_v4_conn_request,中部分代码如下:          ...     case TCP_LISTEN:   if(th->ack) /*监听时收到的ack包都丢弃?*/    return 1;

  if(th->syn) {/*如果是SYN包,则调用tcp_v4_conn_request*/    if(tp->af_specific->conn_request(sk, skb) < 0)     return 1;     ...     四、后记     这里只是给了一个tcp/ip三次握手原理的实现框架简述,结合相关理论教材和这个流程,仔细阅读 linux内核对tcp/ip的实现,对自己理解tcp/ip的精髓不无裨益,期待着与大家一起进步。

关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0872s