加入收藏 | 设为首页 | 会员中心 | 我要投稿 源码门户网 (https://www.92codes.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[十六]:TCP三次握手

发布时间:2016-09-28 12:48:07 所属栏目:Linux 来源:站长网
导读:副标题#e# 内核:2.6.34 TCP是应用最广泛的传输层协议,其提供了面向连接的、可靠的字节流服务,但 也正是因为这些特性,使得TCP较之UDP异常复杂,还是分两部分[创建与使用]来进行分析。这篇主要包括TCP的创建及三次握手 的过程。 编程时一般用如下语句创建

tcp_v4_do_rcv()是TCP模块接收的入口函数,客户端发起请求的对象是listen fd,所以sk->sk_state == TCP_LISTEN ,调用tcp_v4_hnd_req()来检查是否处于半连接,只要三次握手没有完成,这样的连接就称为半连接,具体而言就是收到了SYN ,但还没有收到ACK的连接,所以对于这个查找函数,如果是SYN报文,则会返回listen的socket(连接尚未创建);如果是ACK报 文,则会返回SYN报文处理中插入的半连接socket。其中存储这些半连接的数据结构是syn_table,它在listen()调用时被创建, 大小由sys_ctl_max_syn_backlog和listen()传入的队列长度决定。

此时是收到SYN报文,tcp_v4_hnd_req()返回的仍是sk ,调用tcp_rcv_state_process()来接收SYN报文,并发送SYN+ACK报文,同时向syn_table中插入一项表明此次连接的sk。

if (sk->sk_state == TCP_LISTEN) {     
 struct sock *nsk = tcp_v4_hnd_req(sk, skb);     
 if (!nsk)     
  goto discard;     
 if (nsk != sk) {     
  if (tcp_child_process(sk, nsk, skb)) {     
   rsk = nsk;     
   goto reset;     
  }     
  return 0;     
 }     
}     
TCP_CHECK_TIMER(sk);     
if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {     
 rsk = sk;     
 goto reset;     
}

tcp_rcv_state_process()处理各个状态上socket的情况。下面是处于TCP_LISTEN的代码段,处于TCP_LISTEN的 socket不会再向其它状态变迁,它负责监听,并在连接建立时创建新的socket。实际上,当收到第一个SYN报文时,会执行这段 代码,conn_request() => tcp_v4_conn_request。

case TCP_LISTEN:    

 
……     
 if (th->syn) {     
  if (icsk->icsk_af_ops->conn_request(sk, skb) < 0)     
   return 1;     
  kfree_skb(skb);     
  return 0;     
 }

tcp_v4_conn_request()中注意两个函数就可以了:tcp_v4_send_synack()向客户端发送了SYN+ACK报文, inet_csk_reqsk_queue_hash_add()将sk添加到了syn_table中,填充了该客户端相关的信息。这样,再次收到客户端的ACK报文 时,就可以在syn_table中找到相应项了。

if (tcp_v4_send_synack(sk, dst, 

req, (struct request_values *)&tmp_ext) || want_cookie)     
 goto drop_and_free;     
inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);

*接收客户端发来的ACK

tcp_v4_do_rcv()

过程与收到SYN报文相同,不同点在于syn_table中已经插入了有关该连接的条目,tcp_v4_hnd_req() 会返回一个新的sock: nsk,然后会调用tcp_child_process()来进行处理。在tcp_v4_hnd_req()中会创建新的sock,下面详细看 下这个函数。

if (sk->sk_state == TCP_LISTEN) {     
 struct sock *nsk = tcp_v4_hnd_req(sk, skb);     
 if (!nsk)     
  goto discard;     
 if (nsk != sk) {     
  if (tcp_child_process(sk, nsk, skb)) {     
   rsk = nsk;     
   goto reset;     
  }     
  return 0;     
 }     
}

tcp_v4_hnd_req()

之前已经分析过,inet_csk_search_req()会在syn_table中找到req ,此时进入tcp_check_req()

struct request_sock *req = 

inet_csk_search_req(sk, &prev, th->source, iph->saddr, iph->daddr);     
if (req)     
 return tcp_check_req(sk, skb, req, prev);

tcp_check_req()

syn_recv_sock() - > tcp_v4_syn_recv_sock()会创建一个新的sock并返回,创建的sock状态被直接设置为TCP_SYN_RECV,然后因为此时socket 已经建立,将它添加到icsk_accept_queue中。

(编辑:源码门户网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读