4.7--计算机网络之TCP篇之socket编程--(复习+深入)---好好沉淀,加油呀
1.针对 TCP 应该如何 Socket 编程?
1.服务端和客户端初始化 socket,得到文件描述符;
2.服务端调用 bind,将 socket 绑定在指定的 IP 地址和端口;
3.服务端调用 listen,进行监听;
4.服务端调用 accept,等待客户端连接;
5.客户端调用 connect,向服务端的地址和端口发起连接请求;
6.服务端 accept 返回用于传输的 socket 的文件描述符;
7.客户端调用 write 写入数据;服务端调用 read 读取数据;
8.客户端断开连接时,会调用 close,那么服务端 read 读取数据的时候,就会读取到了 EOF,待处理完数据后,服务端调用 close,表示连接关闭。
服务端调用 accept 时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据。
所以,监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket
2.listen 时候参数 backlog 的意义?
Linux内核中会维护两个队列:
半连接队列(SYN 队列):接收到一个 SYN 建立连接请求,处于 SYN_RCVD 状态;
全连接队列(Accpet 队列):已完成 TCP 三次握手过程,处于 ESTABLISHED 状态;
在早期 Linux 内核: backlog 是 SYN 队列大小,也就是未完成的队列大小。
在 Linux 内核 2.2 之后:backlog 变成 accept 队列,也就是已完成连接建立的队列长度
所以现在通常认为 backlog 是 accept 队列。
但是上限值是内核参数 somaxconn 的大小,也就说 accpet 队列长度 = min(backlog, somaxconn)。
3.accept 发生在三次握手的哪一步?
客户端 connect 成功返回是在第二次握手
服务端 accept 成功返回是在三次握手成功之后
4.客户端调用 close 了,连接是断开的流程是什么?
1.客户端调用 close,表明客户端没有数据需要发送了,则此时会向服务端发送 FIN 报文,进入 FIN_WAIT_1 状态;
2.服务端接收到了 FIN 报文,TCP 协议栈会为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,应用程序可以通过 read 调用来感知这个 FIN 包。这个 EOF 会被放在已排队等候的其他已接收的数据之后,这就意味着服务端需要处理这种异常情况,因为 EOF
表示在该连接上再无额外数据到达。此时,服务端进入 CLOSE_WAIT 状态;
3.接着,当处理完数据后,自然就会读到 EOF,于是也调用 close 关闭它的套接字,这会使得服务端发出一个 FIN 包,之后处于 LAST_ACK 状态;
4.客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进入 TIME_WAIT 状态;
5.服务端收到 ACK 确认包后,就进入了最后的 CLOSE 状态;
6.客户端经过 2MSL 时间之后,也进入 CLOSE 状态
5.没有 accept,能建立 TCP 连接吗?
可以
accpet 系统调用并不参与 TCP 三次握手过程,它只是负责从 TCP 全连接队列取出一个已经建立连接的 socket,用户层通过 accpet 系统调用拿到了已经建立连接的 socket,就可以对该 socket 进行读写操作了。
6.没有 listen,能建立 TCP 连接吗?
可以的
客户端是可以自己连自己的形成连接(TCP自连接),也可以两个客户端同时向对方发出请求建立连接(TCP同时打开),这两个情况都有个共同点,就是没有服务端参与,也就是没有 listen,就能 TCP 建立连接。