终于有人把TCP/IP协议说明白了
以太网TCP通信是上位机开发中经常使用的一种通信方式,西门子S7通信、三菱MC通信及MQTT、OPCUA、ModbusTCP等都是TCP通信协议的典型应用。
很多人在上位机面试时,都会被问到关于TCP通信的一些问题,比如三次握手和四次挥手、TCP与Socket之间的联系等,为了便于大家更好地理解TCP通信,我整理了一套关于TCP与Socket的常见问题汇总。
一、OSI参考模型与TCP/IP参考模型

TCP/IP只是一个协议栈,如果想要实现TCP通信,还需要提供对外的操作接口,就像操作系统提供Win32编程接口一样。TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。
-
连接机制
TCP 是面向连接的传输层协议
UDP 是不需要连接
-
服务对象
TCP 是一对一的两点服务
UDP 支持一对一、一对多、多对多
-
可靠性
TCP 保证数据不丢失、不重复、按需到达
UDP 是尽最大努力交付,不保证交付数据
-
拥塞控制、流量控制
TCP 有拥塞控制和流量控制机制
UDP 则没有拥塞控制和流量控制机制

1、一开始的时候,客户端和服务器都处于CLOSE状态
2、TCP服务器监听某个端口,进入LISTEN监听状态。
3、TCP客户端发出连接请求报文,报文首部SYN=1,同时Seq Num=client_isn,TCP客户端处于SYN_SENT(同步已发送)状态。
4、TCP服务器收到请求报文后,如果同意连接,则发出确认报文,ACK=1,SYN=1,确认号Ack Num=client_isn+1,同时重新初始化一个序列号Seq Num=server_isn,此时TCP服务器处于SYN-RCVD(同步已接收)状态。
5、TCP客户端收到TCP服务器的确认报文后,还要向服务器给出确认,确认报文中,ACK=1,Ack Num=server_isn+1,这个时候,TCP已经建立连接,客户端进入ESTALBSHED(已建立连接)状态。
6、当服务器收到客户端的确认后,也进入ESTALBSHED(已建立连接)状态,这个时候双方就可以开始通信了。

1、一开始的时候,客户端和服务器都是处于ESTABLISHED状态。
2、客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u,此时,客户端进入FIN_WAIT_1(终止等待1)状态。
3、服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。
4、客户端收到服务器的确认请求后,此时,客户端就进入FIN_WAIT_2(终止等待2)状态,等待服务器发送连接释放报文(此时还需要接受服务器发送的最后的数据)。
5、服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST_ACK(最后确认)状态,等待客户端的确认。
6、客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,此时,客户端就进入了TIME_WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2*MSL(最长报文段寿命)的时间后,才进入CLOSE状态。
7、服务器只要收到了客户端发出的确认,立即进入CLOSE状态,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
四次握手:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。
八、为什么挥手需要四次?
1、关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
2、服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
由于服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次。
九、基于Socket开发服务器客户端编程步骤

1)服务器编程步骤:
-
服务端初始化 Socket,得到文件描述符
-
服务端调用 Bind,将绑定在 IP 地址和端口
-
服务端调用 Listen,进行监听
-
服务端调用 Accept,建立客户端连接
-
通过Send向客户端发送消息
-
通过Receive接收客户端消息
2)客户端编程步骤:
-
客户端初始化 Socket,得到文件描述符
-
客户端调用Connect,连接服务器
-
连接成功调用Send向客户端发送消息
-
通过Receive接收客户端消息

整体总结
-
Socket并不是某个语言独有的,基本上所有的语言都有Socket。 -
以C#语言为例,Socket就是一个类,创建并实例化Socket对象,调用Connect实现的就是三次握手,调用Close就是四次挥手。 -
在实际开发中,我们常说的S7、MQTT、OPCUA、Modbus等协议,指的都是应用层的协议,我们大多数情况只需要关注应用层协议。
写在最后
今年8月,历经2年,我出版了一本上位机书籍——《C#上位机开发实战指南》。
大家如果需要购买,可以通过京东旗舰店购买。
-END-
感谢大家阅读,关注我,分享上位机开发技术。
夜雨聆风