如何从python原始套接字中的传入数据包中获取消息

时间:2018-05-31 03:37:23

标签: python python-3.x sockets

我有2个程序(客户端和服务器)并使用python 3编写。

功能:

服务器程序=监控数据包

客户端程序=发送数据包

这是服务器代码:

import socket
from struct import *

def PacketMonitoring(): 
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
    except socket.error as e:
        err = e.args[0]
        print ("Errornya: ",e)
        sys.exit()
    while True:
        packet = sock.recvfrom(65535)
        packet = packet[0]
        ip_header = packet[0:20]
        iphead = unpack ("!BBHHHBBH4s4s", ip_header)
        version_ihl = iphead[0]
        version = version_ihl >> 4
        ihl = version_ihl & 0xF
        iph_length = ihl * 4
        ttl = iphead[5]
        source_addr = socket.inet_ntoa(iphead[8])
        dest_addr = socket.inet_ntoa(iphead[9])
        udp_header = packet[iph_length:iph_length+8]
        udphead = unpack("!HHHH",udp_header)
        source_port = udphead[0]
        dest_port = udphead[1]

        print("\nSource IP address: ",source_addr)
        print("Destination Port: ",dest_port)
        print("Message: ",packet)

if __name__ == "__main__":
    PacketMonitoring()

这是客户端代码:

import socket

def SendPacket(IP,Port):
    clientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server_address = (IP, Port)
    try:
        clientSocket.sendto("Hello".encode(), (server_address))
        print("Packet 1 send")
    except:
        print("Packet Failed to Send")

def Main():
    IP = "192.168.67.101"
    Port = 4000
    SendPacket(IP,Port)
if __name__ == "__main__":
    Main()

从客户端我发送包含消息" Hello"到服务器。如何修复我的代码,以便我可以获取该消息并打印该消息(只是" Hello"在服务器端)。

感谢

2 个答案:

答案 0 :(得分:1)

实际上你几乎就在那里。

udphead元组的第三个元素是UDP数据的长度。您应该将其转换为本机格式(socket.ntohs),然后将其与IP标头长度和UDP标头长度一起使用,以从packet.中选择一个切片:

...
# Convert source address to string:
source_addr = socket.inet_ntop(socket.AF_INET, source_addr)

udp_header_length = 8
source_port = socket.ntohs(udphead[0])
dest_port = socket.ntohs(udphead[1])
udp_payload_length = socket.ntohs(udphead[2])
udp_payload_start = iph_length + udp_header_length
udp_payload = packet[udp_payload_start: udp_payload_start + udp_payload_length]
print("\nSource IP address: ", source_addr)
print("Destination Port: ", dest_port)
print("Message: ", udp_payload.decode())

有几点需要注意:

  • 此处的消息被假定为文本。当然,并非所有UDP数据报都包含文本。
  • UDP数据报不一定都适合一个IP数据包,因此您不必获得整个数据包(但是,当然,> 99%的所有UDP数据报 都适合单个数据包IP数据报,你可以忽略那个)
  • 您尚未适应IPv6,其中IP标头具有不同的格式。您需要查看要区分的version_ihl字节。

由于您正在使用python,因此您可能需要查看scapy,它是为方便编码和解码网络数据包而设计的库。

答案 1 :(得分:0)

对于您实际发送的数据包的结构是waaaayyyy overkill。收到的实际内容是JUST hello的字节数,没有额外的数据包信息。

此外,您必须先将服务器绑定到IP地址/端口,然后才能开始接收服务器。

看看这篇文章,以实现您想要实现的目标。

https://wiki.python.org/moin/UdpCommunication