linux查看tcp源码,从Linux源码看Socket(TCP)Client端的Connect

|->tcp_connect_init 初始化tcp socket|->tcp_transmit_skb 发送SYN包|->inet_csk_reset_xmit_timer 设置SYN重传定时器

tcp_connect_init初始化了一大堆TCP相关的设置,例如mss_cache/rcv_mss等一大堆。而且如果开启了TCP窗口扩大选项的话,其窗口扩大因子也在此函数里进行计算:

tcp_connect_init

|->

tcp_select_initial_window

int

tcp_select_initial_window

(...)

{......(*rcv_wscale) =

0;

if (wscale_ok) {

/* Set window scaling on max possible window

* See RFC1323 for an explanation of the limit to 14

*/

space =

max_t(u32, sysctl_tcp_rmem[

2], sysctl_rmem_max);

space =

min_t(u32, space, *window_clamp);

while (space >

65535 && (*rcv_wscale) <

14) {

space >>=

1;

(*rcv_wscale)++;}}......}

如上面代码所示,窗口扩大因子取决于Socket最大可允许的读缓冲大小和window_clamp(最大允许滑动窗口大小,动态调整)。搞完了一票初始信息设置后,才开始真正的三次握手。 在tcp_transmit_skb中才真正发送SYN包,同时在紧接着的inet_csk_reset_xmit_timer里设置了SYN超时定时器。如果对端一直不发送SYN_ACK,将会返回-ETIMEDOUT。

558c384c6ea47de235b928d638d81bf3.png

重传的超时时间和

/proc/sys/net/ipv4/tcp_syn_retries

息息相关,Linux默认设置为5,建议设置成3,下面是不同设置的超时时间参照图。

193ec972acf06046e411ee68e4849862.png

在设置了SYN超时重传定时器后,tcp_connnect就返回,并一路返回到最初始的inet_stream_connect。在这里我们就等待对端返回SYN_ACK或者SYN定时器超时。

int __inet_stream_connect(

struct socket *sock,...,)

{

// 如果设置了O_NONBLOCK则timeo为0

timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);

......

// 如果timeo=0即O_NONBLOCK会立刻返回

// 否则等待timeo时间

if (!timeo || !inet_wait_for_connect(sk, timeo, writebias))

goto out;

}

Linux本身提供一个SO_SNDTIMEO来控制对connect的超时,不过Java并没有采用这个选项。而是采用别的方式进行connect的超时控制。仅仅就C语言的connect系统调用而言,不设置SO_SNDTIMEO,就会将对应用户进程进行睡眠,直到SYN_ACK到达或者超时定时器超时才将次用户进程唤醒。

1c73f2c166da6213d9abdd478e50934b.png

如果是NON_BLOCK的话,则是通过select/epoll等多路复用机制去捕获超时或者连接成功事件。

对端SYN_ACK到达

在Server端SYN_ACK到达之后会按照下面的代码路径传递,并唤醒用户态进程:

tcp_v4_rcv

|->tcp_v4_do_rcv|->tcp_rcv_state_process|->tcp_rcv_synsent_state_process|->tcp_finish_connect|->tcp_init_metrics 初始化度量统计|->tcp_init_congestion_control 初始化拥塞控制|->tcp_init_buffer_space 初始化buffer空间|->inet_csk_reset_keepalive_timer 开启包活定时器|->sk_state_change(sock_def_wakeup) 唤醒用户态进程|->tcp_send_ack 发送三次握手的最后一次握手给Server端|->tcp_set_state(sk, TCP_ESTABLISHED) 设置为ESTABLISHED状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值