Linux tcp连接状态之SYNC_RECV

1、按tcp/ip协议的描述,tcp三次握手过程,tcp的状态迁移如下所示:

1)、客户端通过connect系统调用向处于LISTEN状态的服务端发送sync请求,客户端进入SYNC_SEND状态;

2)、服务端收到sync报文后,向客户端发送sync+ack报文,服务端进入SYNC_RECV状态;

3)、客户端收到sync+ack后,进入ESTABLISHED状态,并向服务端发送ack,服务端接收到ack后,进入ESTABLISHED状态。

     (sys_connect)          sync
   client(SYNC_SEND)   ---------->    server(LISTEN)
                           sync+ack
   client(SYNC_SEND)   <----------    server(SYNC_RECV)
                            ack
   client(ESTABLISHED) ---------->    server(ESTABLISHED)

2、但Linux的实现跟这里的描述并非完全一致,在Linux里,服务端收到sync报文并向客户端发送sync+ack后,并没有将自己置位SYNC_RECV状态,而是申请了一个request_sock,并将request_sock挂到sock的半连接队列里,等收到客户端的ack时,再从半连接队列里找到request_sock,并将其置位ESTABLISHED,然后挂到全连接队列中。

3、相关实现:

client端:

1)、client端调用connect系统调用发送sync报文,最终调用tcp_v4_connect,在tcp_v4_connect里通过tcp_set_state(sk, TCP_SYN_SENT)将sk状态置位SYNC_SNET;
2)、client收到server的sync+ack后,将状态置为ESTABLISHED。
tcp_v4_rcv
    tcp_v4_do_rcv
        tcp_rcv_state_process
            tcp_rcv_synsent_state_process
                tcp_finish_connect
                    tcp_set_state(sk, TCP_ESTABLISHED)

server端:

tcp_v4_rcv
	tcp_v4_do_rcv
		int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
		{
			//收到sync包时,状态为TCP_LISTEN,条件成立
			if (sk->sk_state == TCP_LISTEN) {
				//这里是从半连接队列的syn_table里找request_sock,
				//1、如果是sync报文,这里返回为空,跳转到tcp_rcv_state_process
				//在函数tcp_rcv_state_process里会创建一个新的request_sock,然后挂到半连接队列里
				//具体流程:tcp_rcv_state_process->tcp_v4_conn_request->tcp_conn_request->inet_csk_reqsk_queue_hash_add
				//2、如果是client的ack报文,则这里返回的nsk为第1步创建的request_sock,并且在tcp_v4_hnd_req->tcp_check_req里
				//将sk->sk_state状态置位SYNC_RECV,然后把request_sock从半连接队列里移除(tcp_check_req->inet_csk_reqsk_queue_removed)
				//具体流程:tcp_v4_hnd_req->tcp_check_req->tcp_v4_syn_recv_sock->tcp_create_openreq_child->inet_csk_clone_lock
				//(newsk->sk_state = TCP_SYN_RECV)
				struct sock *nsk = tcp_v4_hnd_req(sk, skb);
				if (!nsk)
					goto discard;
				//ack时找到的request_sock与sk不是同一个,条件成立
				if (nsk != sk) {
					sock_rps_save_rxhash(nsk, skb);
					//该函数最终调用tcp_rcv_state_process,在tcp_rcv_state_process里判断sk->sk_state状态为SYNC_RECV,
					//并且收到的是ack报文,然后将状态置位ESTABLISHED。
					if (tcp_child_process(sk, nsk, skb)) {
						rsk = nsk;
						goto reset;
					}
					return 0;
				}
			} else
				sock_rps_save_rxhash(sk, skb);

			if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {
				rsk = sk;
				goto reset;
			}
			return 0;
		}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值