一、理论基础一——tcp socket connect详细流程
TCP Socket的connect()系统调用的详细流程,涵盖从应用层到网络层的完整过程:
1、应用层:调用 connect()
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
客户端调用 connect() 发起 TCP 连接请求。
若 Socket 是 阻塞模式(默认),connect() 会阻塞直到连接成功或失败;若为 非阻塞模式,立即返回 EINPROGRESS 错误,需后续轮询或异步通知。
2、传输层:触发三次握手
2.1 客户端发送 SYN 包
内核生成 SYN 报文(TCP 标志位 SYN=1):
源端口:随机选择(或显式绑定)。
目的端口:目标服务器的端口(如 80)。
序列号(ISN):随机初始序列号(防止预测攻击)。
窗口大小:初始接收窗口(如 rwnd=65535)。
选项字段:如 MSS(最大报文段大小)、Window Scaling(窗口 缩放因子)等
状态变化:Socket 状态从 CLOSED 变为 SYN_SENT
2.2 服务器响应 SYN-ACK 包
服务器内核收到 SYN 包后(假设处于 LISTEN 状态)
检查目的端口是否监听,若未监听则回复 RST
若接受连接,生成 SYN-ACK 报文(SYN=1, ACK=1)
确认号(ACK):客户端 ISN + 1
服务器 ISN:随机初始序列号
服务器状态变为 SYN_RCVD,并将连接加入 半连接队列(SYN Queue)
2.3 客户端发送 ACK 包
客户端收到 SYN-ACK 后
验证 ACK 号是否等于客户端 ISN + 1
发送 ACK 报文(ACK=1)确认服务器的 ISN
状态变化:Socket 状态从 SYN_SENT 变为 ESTABLISHED
服务器收到 ACK 后
将连接从半连接队列移到 全连接队列(Accept Queue)
状态变为 ESTABLISHED
3、内核协议栈处理细节
3.1 Socket 状态管理
客户端内核维护一个 TCP 控制块(TCB),记录
本地和远端 IP/端口
当前序列号(snd_nxt)和确认号(rcv_nxt)
窗口大小、RTT(往返时间)、拥塞控制参数等
3.2 超时与重传
若未收到 SYN-ACK
客户端内核启动 超时重传(初始超时时间通常为 1秒,指数退避重试,如 3, 6, 12秒
重试次数由系统参数控制(如 /proc/sys/net/ipv4/tcp_syn_retries,默认 6次)
最终失败返回 ETIMEDOUT 错误
3.3 错误处理
常见错误:
ECONNREFUSED:服务器未监听端口(收到 RST 包)
ENETUNREACH:网络不可达(路由失败)
EHOSTUNREACH:主机不可达(ARP 解析失败)
4、服务器端 accept() 的关联
不做记录。
5、非阻塞模式下的 connect()
不做记录。
6、内核与硬件的协作
数据包发送:
内核将 SYN 包封装成 IP 数据包,交给网卡驱动。
网卡通过 DMA 将数据发送到物理链路。
数据包接收:
网卡通过中断或轮询(NAPI)将 SYN-ACK 包存入内核缓冲区
协议栈解析 TCP 头部,更新 Socket 状态
总结流程:
应用层:connect() → 传输层:发送 SYN → 网络层:路由 → 链路层:发送帧
↓
服务器:SYN → SYN-ACK → 客户端:ACK → 连接建立
↓
应用层:connect() 返回成功(阻塞模式)或异步通知(非阻塞模式)
二、理论基础二——报文处理流程

以上是数据发送过程

以上是数据接收过程

三、连接的一些过程
1、ip_output 函数的定义和作用
确定数据包的路由,发送到合适的网络接口
应该与这个ENETUNREACH对应
如果需要,还会将数据包分片
2、dst_neigh_output
通常位于 Linux 内核的路由和邻居子系统中
如果邻居项尚未存在或无效,触发 ARP(IPv4)或 NDP(IPv6)请求,进行地址解析,这块记录一下
arp_get_hwaddr

这块找不到目标地址会触发arp广播。

之后触发tcp_connect_rto函数。
tcp_connect_rto 函数的作用是 为 TCP 连接的 SYN 报文(三次握手阶段)计算初始的重传超时时间(RTO, Retransmission Timeout),确保在 SYN 报文未收到确认(SYN-ACK)时,客户端能够合理触发超时重传。
如果正常就是三次握手流程!
欢迎关注:
如有需要红包封面定制可在公众号后台留言!
其他网络协议栈相关:
3万+

被折叠的 条评论
为什么被折叠?



