Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 操作系统 > Linux > 三次握手协议在linux内核中的实现
【标  题】:三次握手协议在linux内核中的实现
【关键字】:linux
【来  源】:http://blog.csdn.net/jccz_zys/archive/2007/02/06/1503252.aspx

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

Your Ad Here

以下基于linux内核2.4.0源码(转载请注明出处)

    以前一直使用的网络通讯的函数都是工作在阻塞模式。在看connect实现源码时,突然想到tcp/ip的
三次握手在内核如何实现的,尤其是在非阻塞模式下式,涉及到等待对端回送ack包,而本端又要立即返
回,想来这种实现肯定是遵循某种规则或是将所有的相关函数组合起来。
    查看一些网络通信书籍,可知果然如此。应用编程如果设置为非阻塞模式,则连接时,connect发送
SYN包后立即返回-EINPROGRESS,表示操作正在处理中;随后应用可以在connect返回后做一些其它的处理,
最后在select函数中来捕获socket的连接、读写、异常事件以触发相关操作,下面我们看看内核中的相关
实现:
一、tcp/ip连接的三次握手过程:
      client    SYN包--->                    server
      client    <---SYN包+ACK包      server
      client    ACK包--->                    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 ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
  /* 错误返回码err前面已经设置 */
  if (!timeo || !inet_wait_for_connect(sk, timeo))
  /*注意上面所判断的2中情况,1、如果是非阻塞模式,则!timeo为1,则直接跳到out返回-EINPROGRESS结束connect函数
    2、若为阻塞模式,则在inet_wait_for_connect函数中通过schedule_timeout函数放弃cpu控制权睡眠,等待服务器端
    发送ACK响应包后被唤醒继续处理。如果没有异常出现,则置socket状态为SS_CONNECTED,表示连接成功,正确返回
  */
   goto out;
  
  err = sock_intr_errno(timeo);
  if (signal_pending(current)) /*处理未决信号*/
   goto out;
 }
 ...
 sock->state = 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_v4_send_synack中的部分代码:  
    /*生成要发送的ACK包*/
    skb = tcp_make_synack(sk, dst, req);

    if (skb) {
     struct tcphdr *th = skb->h.th;
   
     th->check = tcp_v4_check(th, skb->len,  /*计算校验和*/
         req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr,
         csum_partial((char *)th, skb->len, skb->csum));
    
     /*传送到IP层,做iptable授权判断及发送处理*/
     err = ip_build_and_send_pkt(skb, sk, req->af.v4_req.loc_addr,
            req->af.v4_req.rmt_addr, req->af.v4_req.opt);
     if (err == NET_XMIT_CN)
      err = 0;
    }
    ...


四、后记
    这里只是给了一个tcp/ip三次握手原理的实现框架简述,结合相关理论教材和这个流程,仔细阅读
linux内核对tcp/ip的实现,对自己理解tcp/ip的精髓不无裨益,期待着与大家一起进步。     

squid 发布新的官方网站:【上一篇】
什么是Moodle?:【下一篇】
【相关文章】
  • 用机器生成的音乐监控 Linux 计算机
  • 在 Cell BE 处理器上编写高性能的应用程序,第 1 部分: 简介 PLAYSTATION 3 上的 Linux
  • linux下apache,mysq,lphp,Zend Optimizer的配置日志
  • linux下修改用户的默认组
  • Linux下Ping的实现代码
  • 最先进的Linux内核正式发布
  • Linux中关于hostname的设置
  • Linux下Zend Studio中文乱码的解决
  • linux下读取键盘扫描码
  • 关于Linux下C/C++程序编译
  • 【随机文章】
  • 让Axis支持EMF模型
  • 抛砖引玉: 正则的几个基本概念
  • Freehand图形特效处理
  • 超级简单但超级实用的 PHP 的 mysql 类
  • Illustrator网络渐变教程
  • 安全第一:.NET加密技术指南
  • 在工作簿中使用Excel工作表
  • 软交换网络多媒体业务的实现(1)
  • LINUX 常见问题
  • PVR简介
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.