Python 原始套接字监听 UDP 数据包;只收到一半的数据包 [英] Python raw socket listening for UDP packets; only half of the packets received

查看:69
本文介绍了Python 原始套接字监听 UDP 数据包;只收到一半的数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Python 中创建一个 raw 套接字,该套接字仅侦听 UDP 数据包:

导入套接字s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)s.bind(('0.0.0.0', 1337))为真:打印 s.recvfrom(65535)

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

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

导入套接字c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)c.connect(('127.0.0.1', 1337))c.send('消息1')c.send('消息2')c.send('消息3')c.send('消息4')c.send('消息5')c.send('消息 6')

一致地,只有第一条、第三条和第五条消息(message 1message 3message 5)会通过并被打印在服务器输出中.第二条、第四条和第六条消息没有显示在服务器输出上,而是客户端得到一个异常:

<预><代码>>>>c.send('消息2')回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中socket.error: [Errno 111] 连接被拒绝

在 Wireshark 中运行它表明它正在收到目标无法访问"的 ICMP 回复.我已经能够在 3 台不同的机器上重现这个(尽管都运行 Linux).我错过了什么吗?这是 UDP 持续丢弃数据包的预期行为,因为使用它的协议应该可以容忍数据包丢失?即便如此,为什么数据包在本地接口上发送时会被丢弃?

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

解决方案

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

解决办法很简单,就是使用绑定在同一个端口上的两个socket;一个生的,一个不是生的:

导入socket,选择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))为真:r, w, x = select.select([s1, s2], [], [])对于 r 中的 i:打印 i, i.recvfrom(131072)

这会使目标无法到达"ICMP 数据包消失,并使所有数据包都能正常通过.我认为操作系统需要一个非原始套接字监听端口以便一切顺利,然后任何监听同一端口的原始套接字都会收到数据包的副本.

I am trying to create a raw socket in Python that listens for UDP packets only:

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)

This needs to be run as root, and creates a raw socket on port 1337, which listens for UDP packets and prints them whenever they are received; no problems there.

Now let's make a little client to test if this works:

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')

Consistently, only the first, third, and fifth message (message 1, message 3 and message 5) will get through and be printed in the server output. The second, fourth, and sixth messages do not show up on the server output, and instead the client gets an exception:

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

Running this in Wireshark shows that it is getting an ICMP reply for "Destination unreachable". I have been able to reproduce this on 3 distinct machines (all running Linux though). Am I missing something? Is this expected behaviour for UDP to consistently drop packets, since protocols using it are supposed to be tolerant of packet loss? Even so, why would packets be dropped when sent on the local interface?

Binding the server to 127.0.0.1 instead of 0.0.0.0 has the same result.

解决方案

Solved it in kind of a silly manner; please let me know if there is another way, and I will change the accepted answer.

The solution is simply to use two sockets bound on the same port; one raw, one not raw:

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)

This makes the "Destination unreachable" ICMP packets go away and makes all packets go through fine. I think the operating system wants a non-raw socket listening on the port for things to go well, and then any raw sockets listening on that same port will receive copies of the packets.

这篇关于Python 原始套接字监听 UDP 数据包;只收到一半的数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆