TCP协议客户端与服务器端一般的通信过程

服务器初始化
(1)调用socket,创建文件描述符
(2)调用bind,将文件描述符与ip/port连接起来。若端口号已被占用,则bind失败
(3)调用listen,声明该文件描述符是服务器的一个文件描述符,为之后的accept做准备
(4)调用accept,并处于阻塞状态,等待客户端连接
建立连接
(1)调用socket,创建文件描述符
(2)调用connect,向服务器发起连接请求。
(3)connect会发送一个请求SYN段并阻塞等待服务器应答(第一次)
(4)服务器收到SYN,会给客户端发送一个确认应答的同时发送一个请求(SYN+ACK),表示同意建立连接(第二次)
(5)客户端收到客户端发的SYN+ACK段,表明客户端连接已建立成功,进入ESTABLISHED状态,从connect()。客户端再向服务器发送一个ACK段,服务器收到后则服务器端连接也建立成功,服务器也进入ESTABLISHED状态。
TCP协议客户端与服务器端一般的通信过程
数据传输
(1)连接建立成功后,在同一连接、同一时刻,通信双方可同时写数据(全双工)
(2)服务器端从accept()返回后调用read()开始读数据,若没有数据则阻塞等待
(3)客户端调用write()向服务器发送数据请求,客户端收到之后调用read()处理请求,此过程服务器调用read()阻塞等待
(4)服务器调用write()将处理好的请求发送给客户端,再次调用read()等待下一个请求
(5)客户端收到后从read()返回,发送下一条请求,如此循环下去

断开连接
(1)没有数据处理了,则客户端调用close()关闭连接,给服务器端发送一个断开连接请求FIN段(第一次)
(2)服务器收到客户端的FIN段,给客户端发送一个确认应答ACK段表明同意断开连接,客户端收到ACK段并调用read()返回0,表明客户端连接已断开(第二次)
(3)read()返回0之后,服务器知道客户端已断开连接,它也调用close()关闭连接,给客户端发送一个断开连接请求FIN段(第三次)
(4)客户端接收到服务器端发送的FIN段,给服务器一个确认应答ACK段,表明同意断开连接。客户端进入TIME_WAIT状态,服务器收到客户端的ACK后则服务器断开连接。
TCP协议客户端与服务器端一般的通信过程

总结
1.为什么是三次握手而不是两次或四次握手?
(1)如果是两次握手,则客户端发送连接请求SYN,服务器端接收连接请求并给客户端发送一个ACK进入ESTABLISHED状态,服务器端认为连接建立成功。有可能服务器端发送的ACK在传输过程中丢了,客户端没有收到ACK从而认为连接没有建立成功。客户端认为连接没有建立成功则会不停的发送连接请求,而服务器认为连接成功则需要文虎相应的资源来管理连接,但这个连接无意义,服务器在维护的时候会浪费服务器资源。造成空间与时间上的浪费,从而造成内存泄漏的问题。四次握手问题同二次握手。
(2)三次握手的最后一次传送数据有可能也会造成丢包问题,但是此时客户端认为连接建立成功而服务器认为连接建立没成功,对服务器没有太大的消耗。客户端给服务器端发送数据,服务器端不进行接收。
三次握手已经满足需求就不需要更多次的握手。
(3)建立连接是双方的事情,双方都需要建立连接再互相确认,有点像四次握手。但是因为因为TCP能捎带应答,所以服务器向客户端的请求建立连接的SYN以及对客户端的ACK可以一起发送,从而导致了三次握手。
2.为什么是四次挥手?
* 释放连接是两方的事情,双方发送断开连接请求后还需要确认,而且服务器对客户端的ACK以及FIN不能合并,所以是四次挥手
* 服务器端对客户端的FIN及ACK不能合并是因为客户端断开连接表明客户端没有数据发送给服务器了,不带表服务器没有数据发给客户端,则服务器向客户端发送ACK之后到服务器发送FIN之间有时间间隔,所以两步骤不能合并
3.为什么有TIME_WAIT状态?
如服务器端将最后一个断开连接请求发送之后,客户端收到FIN后给服务器端发送一个确认应答ACK,但在传输过程中可能会丢包,这个ACK没有被服务器收到。当服务器在一定时间内没有收到ACK时会重新发送请求,所以客户端需要一个TIME_WAIT时间等待,解决丢包重传问题。一个TIME_WAIT的时间是2MSL。
哪一方先断开连接就先进入TIME_WAIT等待时间。