TCP协议通讯原理

TCP通讯时序图
这里写图片描述

在上面这个例子中,首先客户端主动发起连接、发送请求,然后服务器端响应请求,然后客户端主动关闭连接。
建⽴立连接的过程:
1. 客户端发出段1,SYN位表⽰示连接请求。序号是1000,这个序号在网络通讯中用作临时的地 址,每发一个数据字节,这个序号要加1,这样在接收端可以根据序号排出数据包的正确顺 序,也可以发现丢包的情况,另外,规定SYN位和FIN位也要占一个序号,这次虽然没发数 据,但是由于发了SYN位,因此下次再发送应该用序号1001。mss表示最大段尺寸,如果一 个段太大,封装成帧后超过了链路层的最大帧长度,就必须在IP 层分片,为了避免这种情 况,客户端声明自己的最大段尺寸,建议服务器端发来的段不要超过这个长度。
2. 服务器发出段2,也带有SYN位,同时置ACK位表示确认,确认序号是1001,表⽰示“我接收到 序号1000及其以前所有的段,请你下次发送序号为1001的段”,也就是应答了客户端的连接 请求,同时也给客户端发出一个连接请求,同时声明最⼤大尺⼨寸为1024。
3. 客户端发出段3,对服务器的连接请求进行应答,确认序号是8001。 
在这个过程中,客户端和服务器分别给对方发了连接请求,也应答了对方的连接请求,其中服务器 的请求和应答在一个段中发出,因此一共有三个段用于建立连接,称为”’⽅方握手(three-way-handshake)”’。在建立连接的同时,双方协商了⼀一些信息,例如双方发送序号的初始值、最大段尺寸等。
数据传输的过程:
1. 客户端发出段4,包含从序号1001开始的20个字节数据。
2. 服务器发出段5,确认序号为1021,对序号为1001-1020的数据表⽰示确认收到,同时请求发送 序号1021开始的数据,服务器在应答的同时也向客户端发送从序号8001开始的10个字节数 据,这称为piggyback 。
3. 客户端发出段6,对服务器发来的序号为8001-8010的数据表⽰示确认收到,请求发送序号8011开始的数据。
在数据传输过程中,ACK和确认序号是非常重要的,应用程序交给TCP协议发送的数据会暂存在TCP层的发送缓冲区中,发出数据包给对方之后,只有收到对方应答的ACK段才知道该数据包确 实发到了对方,可以从发送缓冲区中释放掉了,如果因为网络故障丢失了数据包或者丢失了对方发回的ACK段,经过等待超时后TCP协议自动将发送缓冲区中的数据包重发。
关闭连接的过程:
1. 客户端发出段7,FIN位表示关闭连接的请求。
2. 服务器发出段8,应答客户端的关闭连接请求。
3. 服务器发出段9,其中也包含FIN位,向客户端发送关闭连接请求。
4. 客户端发出段10,应答服务器的关闭连接请求。
建立连接的过程是三方握手,而关闭连接通常需要4个段,服务器的应答和关闭连接请求通常不合 并在一个段中,因为有连接半关闭的情况,这种情况下客户端关闭连接之后就不能再发送数据给服务器了,但是服务器还可以发送数据给客户端,直到服务器也关闭连接为止。
为什么TCP建立连接是三次握手
三次是能保证正确通讯的最低保证,首先client端发送SYN请求给server,server接收到后发送应答ACK并发送连接请求SYN,client此时发送ACK应答,完成连接。
为什么不是两次呢?
因为如果两次就认为连接成功,client发送SYN给server,server此时发送应答ACK和SYN给client,若此时client未接受到消息,此时server端认为已经建立连接,但client认为未建立连接,会反复申请,此时server端将会保存大量的连接信息,若client大量请求,server端可能会崩溃。
为什么不是四次或者更多呢?
因为三次在大多数情况下已经能保证通讯已经建立,四次显得冗余。很多人认为多互相多发几次可以有效的保证连接建立,但通讯中的最后一次发送永远都不能保证对方已接受。所以三次握手成了TCP建立连接的标准。
世界上不存在完全可靠的通信协议。

### Modbus TCP通信协议的工作原理 #### 1. 协议基础 Modbus TCP是一种基于以太网的通信协议,它是传统Modbus协议在网络层面上的扩展。通过TCP/IP协议栈的支持,Modbus TCP能够在局域网或广域网上实现高效的数据传输[^2]。 #### 2. 数据帧结构 Modbus TCP的消息封装在标准的TCP数据包中。它的消息帧由以下几个部分组成: - **事务标识符 (Transaction Identifier)**:用于匹配请求和响应消息。 - **协议标识符 (Protocol Identifier)**:通常固定为0,表示这是一个标准的Modbus TCP报文。 - **长度字段 (Length Field)**:指示后续字节的数量。 - **单元标识符 (Unit Identifier)**:指定目标设备地址。 - **PDU (Protocol Data Unit)**:即传统的Modbus应用层数据单元,包含功能码和数据区[^1]。 #### 3. 功能码的作用 Modbus TCP支持多种功能码来定义具体的操作行为。以下是常见的功能码及其用途: - `0x01`:读取线圈状态。 - `0x02`:读取离散输入状态。 - `0x03`:读取保持寄存器。 - `0x04`:读取输入寄存器。 - `0x05`:写单个线圈。 - `0x06`:写单个寄存器。 - `0x0F`:写多个线圈。 - `0x10`:写多个寄存器[^3]。 每种功能码对应特定的应用场景,例如监控传感器状态、控制执行机构动作或者批量更新参数设置。 #### 4. 客户端与服务器交互流程 在一个典型的Modbus TCP通信环境中,存在客户端(Master)和服务端(Slave)。它们之间遵循以下基本交互逻辑: - 客户端发送带有明确指令的功能码至服务端。 - 服务端接收并解析该命令后返回相应的结果集给客户端。 整个过程依赖于可靠的连接机制以及精确的时间同步管理策略。 ```python import socket def modbus_tcp_request(host, port=502): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) # 构造简单的MODBUS 请求头 + PDU 示例 transaction_id = b'\x00\x01' # Transaction ID protocol_id = b'\x00\x00' # Protocol ID always zero for MODBUS/TCP length_field = b'\x00\x06' # Length of the following fields in bytes unit_id = b'\x01' # Slave/Unit Address function_code = b'\x03' # Example Function Code: Read Holding Registers start_addr = b'\x00\x00' # Starting address to read from quantity = b'\x00\x0A' # Number of registers to read request_frame = transaction_id + protocol_id + length_field + unit_id + \ function_code + start_addr + quantity sock.send(request_frame) response_data = sock.recv(1024) print("Response:", response_data.hex()) except Exception as e: print(f"Error occurred during communication: {e}") finally: sock.close() modbus_tcp_request('192.168.1.1') ``` 上述代码片段展示了如何利用Python构建一个简易版的Modbus TCP查询工具,向远程主机发起读取操作,并打印接收到的结果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值