首页 文章

Python原始套接字监听UDP数据包;只收到一半的数据包

提问于
浏览
7

我试图在Python中创建一个仅监听UDP数据包的 raw 套接字:

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
s.bind(('0.0.0.0', 1337))
while True:
    print s.recvfrom(65535)

这需要以root身份运行,并在端口1337上创建一个原始套接字,它接收UDP数据包并在收到它们时打印它们;没有问题 .

现在让我们做一个小客户端来测试它是否有效:

import socket
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.connect(('127.0.0.1', 1337))
c.send('message 1')
c.send('message 2')
c.send('message 3')
c.send('message 4')
c.send('message 5')
c.send('message 6')

始终如一,只有第一个,第三个和第五个消息( message 1message 3message 5 )将通过并打印在服务器输出中 . 第二,第四和第六条消息未显示在服务器输出上,而是客户端获得异常:

>>> c.send('message 2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.error: [Errno 111] Connection refused

在Wireshark中运行它表明它正在获取“目标无法访问”的ICMP回复 . 我已经能够在3台不同的机器上重现这一点(所有机器都在运行Linux) . 我错过了什么吗? UDP的这种预期行为是否始终丢弃数据包,因为使用它的协议应该容忍数据包丢失?即便如此,为什么在本地接口上发送数据包会被丢弃?

将服务器绑定到 127.0.0.1 而不是 0.0.0.0 具有相同的结果 .

1 回答

  • 8

    以某种愚蠢的方式解决了它;如果有其他方法,请告诉我,我会更改已接受的答案 .

    解决方案只是使用绑定在同一端口上的两个套接字;一个原始的,一个不是原始的:

    import socket, select
    s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s1.bind(('0.0.0.0', 1337))
    s2 = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
    s2.bind(('0.0.0.0', 1337))
    while True:
        r, w, x = select.select([s1, s2], [], [])
        for i in r:
            print i, i.recvfrom(131072)
    

    这使得“目的地不可达”ICMP数据包消失,使所有数据包都能正常运行 . 我认为操作系统需要一个非原始套接字监听端口以便事情顺利进行,然后在同一端口上侦听的任何原始套接字都将接收数据包的副本 .

相关问题