1. 完整的代码如下:
import socket
import binascii
class Omron:
def __init__(self, ip, port=9600):
self.ip = ip # PLC的IP地址
self.port = port # PLC的端口,默认为9600
def send_receive_fins(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sc:
sc.settimeout(30) # 设置socket超时时间为30秒
try:
sc.connect((self.ip, self.port)) # 尝试连接到PLC
sc.send(binascii.unhexlify('46494e530000000c000000000000000000000000')) # 发送初始化包
response = sc.recv(4096) # 接收PLC的响应
if binascii.hexlify(response)[:4] != b'4649': # 检查响应是否以'FINS'开始
return False
# 第一部分:FINS/TCP Header 字段信息
magic_bytes = "46494e53" # FINS, 4个字节
# 修改:需要根据写入数据的长度来设置长度字段
length = "0000002c" # length以后所有字段的长度,4个字节
# 修改:需要根据写入数据的长度来设置长度字段
command = "00000002" # 发送帧,4个字节
error_code = "00000000" # 错误码,4个字节
# 第二部分:FINS Header 字段信息
information_control_field = "80" # 信息控制字段,1个字节
reserved = "00" # 保留,1个字节
gateway_count = "02" # 网关数
destination_network_address = "00" # 目标网络地址,1个字节
destination_node_number = self.extract(response, 46) # 提取PLC返回的server_node_address
destination_unit_address = "00" # 目标单元地址,1个字节
source_network_address = "00" # 源网络地址,1个字节
source_node_number = "00" # 源节点地址,1个字节
source_unit_address = "ef" # 源单元地址,1个字节
# 修改部分
service_id = "00" # 服务ID,此处为00,表示读取数据,1个字节
command_code = "0102" # 命令代码,此处为内存区域写入,2个字节
memory_area_code = "82" # 内存区域代码,1个字节,此处为82,表示为PLC的DM区域
beginning_address = "006400" # 起始地址,3个字节,此处为0x6400
item_count = "0009" # 写9个字的数据,2个字节,一个字为2个字节
data = "617164627432707737396d306964746b3833" # 待写入的数据,# len(data) = item_count * 2 = 18字节
# 修改部分
cmd_packet = magic_bytes + \
length + \
command + \
error_code + \
information_control_field + \
reserved + \
gateway_count + \
destination_network_address + \
destination_node_number + \
destination_unit_address + \
source_network_address + \
source_node_number + \
source_unit_address + \
service_id + \
command_code + \
memory_area_code + \
beginning_address + \
item_count + \
data
print('cmd_packet:', binascii.unhexlify(cmd_packet))
sc.send(binascii.unhexlify(cmd_packet)) # 发送指令包
response = sc.recv(1024) # 接收PLC的响应
except Exception as e:
print(f"连接或传输错误: {e}") # 输出错误信息
return False
@staticmethod
def extract(data, offset):
hex_data = binascii.hexlify(data).decode() # 将数据转换为十六进制字符串
return hex_data[offset:offset + 2] # 返回指定位置的数据
if __name__ == '__main__':
omron_plc = Omron('89.186.98.168', 9600) # 实例化Omron类,设置IP和端口
print(omron_plc.send_receive_fins()) # 发送请求并打印返回的PLC信息
2. 需要修改的字段包括:length、service_id、 command_code、memory_area_code、 beginning_address 、item_count、data,具体如下:
length = TCP length - 8 = 24 + item_count的字节数 + item_count (十进制)* 2
length = "0000002c"
command = "00000002" # 4个字节
error_code = "00000000" # 4个字节
# 第二部分:FINS Header 字段信息
information_control_field = "80" # 1个字节
reserved = "00" # 1个字节
gateway_count = "02" # 1个字节
destination_network_address = "00" # 1个字节
destination_node_number = self.extract(response, 46) # 1个字节
destination_unit_address = "00" # 1个字节
source_network_address = "00" # 1个字节
source_node_number = "00" # 1个字节
source_unit_address = "ef" # 1个字节
# 修改部分
service_id = "00" # 1个字节
command_code = "0102" # 2个字节
memory_area_code = "82" # 1个字节
beginning_address = "006400" # 3个字节
item_count = "0009" # 2个字节,写9个字的数据,一个字为2个字节
data = "617164627432707737396d306964746b3833" # len(data) = item_count * 2 = 18字节
3. 捕获的数据包如下: