如何修改Python原始套接字服务端代码提取UDP数据包中的消息?
提取UDP数据包中的消息内容
我来帮你搞定这个问题——现在你的服务端打印的是整个数据包(包含IP头、UDP头和实际消息内容),我们只需要定位到UDP负载的起始位置,提取并解码这部分内容就能只打印"Hello"了。
修改思路
- UDP头固定为8字节,加上IP头的长度(
iph_length),就能得到实际消息的起始索引:iph_length + 8 - 从这个索引开始截取数据包的剩余部分,就是客户端发送的字节数据
- 将字节数据解码为字符串(客户端用
encode()默认采用UTF-8编码,解码时对应使用utf-8即可) - 另外要修正原代码中缺失的
sys模块导入,否则sys.exit()会触发报错
修改后的完整服务端代码
import socket import sys # 补充导入sys模块,修复exit报错 from struct import * def PacketMonitoring(): try: sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP) except socket.error as e: print("Errornya: ", e) sys.exit() while True: packet = sock.recvfrom(65535)[0] # 解析IP头 ip_header = packet[0:20] iphead = unpack("!BBHHHBBH4s4s", ip_header) version_ihl = iphead[0] ihl = version_ihl & 0xF iph_length = ihl * 4 # 定位UDP负载起始位置,提取并解码消息 udp_payload_start = iph_length + 8 # IP头长度 + UDP头长度(固定8字节) message = packet[udp_payload_start:].decode('utf-8') # 获取源IP和目标端口 source_addr = socket.inet_ntoa(iphead[8]) dest_port = unpack("!HHHH", packet[iph_length:iph_length+8])[1] print("\nSource IP address: ", source_addr) print("Destination Port: ", dest_port) print("Message: ", message) # 仅打印解码后的实际消息 if __name__ == "__main__": PacketMonitoring()
关键修改点说明
- 补充
sys模块导入:原代码使用了sys.exit()但未导入sys,会导致运行时抛出NameError - 计算负载起始位置:通过
iph_length + 8跳过IP头和UDP头,直接定位到实际消息内容 - 解码字节数据:将截取到的字节数据用
decode('utf-8')转换为可读字符串 - 优化端口获取:可以直接在解包UDP头时获取目标端口,避免重复操作(原写法也可正常运行,这里是小优化)
这样修改后,服务端就会精准打印客户端发送的"Hello"消息了。
内容的提问来源于stack exchange,提问作者M. Arie




