如图所示打上断点,分别找出connect() bind() listen() accpet()对应的函数
源码在上一次作业中已经分析过了
https://www.cnblogs.com/qwertyue/p/12067806.html
具体过程
下图即TCP编程的步骤
服务器调用listen进行监听
客户端调用connect来发送syn报文
服务器协议栈负责三次握手的交互过程。连接建立后,往listen队列中添加一个成功的连接,直到队列的最大长度。
服务器调用accept从listen队列中取出一条成功的tcp连接,listen队列中的连接个数就少一个
接下来分析4个函数的作用
1 connect()
accept默认会阻塞进程,直到有一个客户连接建立后返回
4 三次握手的连接队列
三次握手如下图所示
已知内核会为任何一个给定的监听套接口维护一个队列,该队列由两部分构成,分别是完成连接接队列、未完成连接队列:
1、未完成连接队列(incomplete connection queue),当服务器每收到客户端的一个SYN分节,就会将该客户端放入未完成连接队列,而服务器套接口处于 SYN_RCVD 状态。
2、已完成连接队列(completed connection queue),当客户端和服务器彻底完成三次握手过程,客户端将从未完成连接队列升级成已完成连接队列,并从未完成连接队列中清空该客户端,这些套接口处于 ESTABLISHED 状态。
当来自客户的 SYN 到达时,TCP 在未完成连接队列中创建一个新项
然后响应以三次握手的第二个分节:服务器的 SYN 响应,其中稍带对客户 SYN 的 ACK(即SYN+ACK),这一项一直保留在未完成连接队列中,直到三次握手的第三个分节(客户对服务器 SYN 的 ACK )到达或者该项超时为止。
如果三次握手正常完成,该项就从未完成连接队列移到已完成连接队列的队尾。
那么内核如何得知连接队列的长度呢?
通过listen() 函数的第二个参数( backlog),它会告知内核连接队列的长度。
backlog 参数历史上被定义为上面两个队列的大小之和,大多数实现默认值为 5,当服务器把这个完成连接队列的某个连接取走后,这个队列的位置又空出一个,这样来回实现动态平衡。
6 总结
TCP的三次握手是由客户端调用connect()以及服务器端的协议栈共同完成的。
服务器端的listen()负责监听客户端的连接请求,并维护一个listen队列,当有客户端连接成功时,就把它放在listen队列里。
accept()函数负责查看listen队列里面有没有成功连接,如果有则从队列中取出,没有则阻塞(直到获得一个成功连接返回)。它每取出一个成功连接,就会生成一个对应的accept fd,用于唯一标识该连接成功的客户端。