当前位置: 首页 > 工具软件 > ack > 使用案例 >

网络篇之三次握手(ACK)

贺皓
2023-12-01

网络篇之socket

网络篇之bind

网络篇之listen

网络篇之accept

网络篇之connect

网络篇之三次握手(SYN+ACK) 

一 客户端发送ACK

 客户端接收到服务端发送的SYN+ACK包后,依然会走到tcp_rcv_state_process方法中,此时客户端是SYN_SENT状态,调用tcp_rcv_synsent_state_process继续处理。

tcp_rcv_synsent_state_process中调用tcp_finish_connect将客户端状态改成设置为TCP_ESTABLISHED状态;调用tcp_send_ack继续处理。

void tcp_send_ack(struct sock *sk)
{
	struct sk_buff *buff;

	/* If we have been reset, we may not send again. */
	if (sk->sk_state == TCP_CLOSE)
		return;

	tcp_ca_event(sk, CA_EVENT_NON_DELAYED_ACK);

	/* We are not putting this on the write queue, so
	 * tcp_transmit_skb() will set the ownership to this
	 * sock.
	 */
	buff = alloc_skb(MAX_TCP_HEADER,
			 sk_gfp_mask(sk, GFP_ATOMIC | __GFP_NOWARN));
	if (unlikely(!buff)) {
		inet_csk_schedule_ack(sk);
		inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN;
		inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
					  TCP_DELACK_MAX, TCP_RTO_MAX);
		return;
	}

	/* Reserve space for headers and prepare control bits. */
	skb_reserve(buff, MAX_TCP_HEADER);
	tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK);

	/* We do not want pure acks influencing TCP Small Queues or fq/pacing
	 * too much.
	 * SKB_TRUESIZE(max(1 .. 66, MAX_TCP_HEADER)) is unfortunately ~784
	 */
	skb_set_tcp_pure_ack(buff);

	/* Send it off, this clears delayed acks for us. */
	tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0);
}

此函数中主要的逻辑有:

1. 调用alloc_skb申请sk_buff结构;

2. 在tcp_init_nondata_skb中将TCP_SKB_CB(skb)->tcp_flags置为TCPHDR_ACK;

#define TCPHDR_ACK 0x10

3. 调用tcp_transmit_skb组装tcp头和ip头并发送。

以下为tcp_transmit_skb中设置tcp头的地方:

th->source = inet->inet_sport; // 源端口

th->dest = inet->inet_dport; // 目标端口

th->seq = htonl(tcb->seq);

th->ack_seq = htonl(tp->rcv_nxt);

// 设置首部长度和ACK标记

*(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |

tcb->tcp_flags);

ip_queue_xmit中调用ip_copy_addrs,设置源/目标地址

memcpy(&iph->saddr, &fl4->saddr, sizeof(fl4->saddr) + sizeof(fl4->daddr));

 最后在ip_queue_xmit中调用ip_local_out将数据包发送出去。

二 服务端接收ACK

还是回到服务端tcp_rcv_state_process函数中,此时服务端处于SYN_RCVD状态,走TCP_SYN_RECV分支。

tcp_set_state(sk, TCP_ESTABLISHED); 设置为ESTABLISHED状态

 类似资料: