使用SO_REUSEADDR通过不同的套接字发送和接收数据包

时间:2013-11-30 11:33:10

标签: python sockets python-2.7 udp

作为此问题的延续:Is it possible to send and receive packets through different sockets?

我尝试过使用SO_REUSEADDR(在意识到我无法使用SO_REUSEPORT之后)。 但是,我的代码仍无效。

这是:

HOST='127.0.0.1'
PORT=10000
recvSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

sendSock.bind((HOST,PORT))
sendSock.sendto("",(HOST,PORT))

recvSock.bind((HOST,PORT))
response,addr = recvSock.recvfrom(65535)

我在第一个'bind'行遇到错误(绑定sentock)。

如果我省略sendSock.bind行,我会在recvSock.recvfrom行上收到错误。

我省略了省略setsockopt线和绑定线的错误,所以我想我使用setsockopt来将两个套接字绑定到同一个地址是不好的。

在互联网上找不到如何使用它们的例子...... 有什么帮助吗?

P.S在Windows XP上使用python 2.7。

1 个答案:

答案 0 :(得分:0)

我怀疑这种方法对你不起作用,但我可能错了。我没有要测试的XP盒子,现代Windows以各种方式限制原始套接字XP没有。但是我会给你更多的信息,试图帮助解释它为什么不起作用,为什么可能无法正常工作,以及你可以试试的。


但首先,让我解释正确在Windows上执行此操作的方式:SIO_RCVALL。像这样:

recvSock.ioctl(socket.SIO_RCVALL, socket.RCVALL_IPLEVEL)

这告诉Windows将发往您计算机的所有IP数据包传递到此套接字。 (也可以发送一些发往其他计算机的数据包,但一般情况下它们不会发送。如果您想要它们,则需要将NIC置于混杂模式,而RCVALL_ON代替。)

请注意,“所有数据包”表示您不关心的大量数据包,因此您需要对其进行过滤。换句话说,您不需要读取一个数据包,而是需要继续读取数据包,检查其本地地址并跳过它们,直到找到所需的数据包为止。

使用SIO_RCVALL时,请勿尝试将套接字绑定到特定主机和端口。有许多问题可以让它正常工作,在Windows上从版本变为版本,并且不值得努力。并且实际上没有任何好处 - Windows仍然会提供至少一些用于其他端口的数据包,因此您仍然需要过滤它们。


或者,您可以将winpcapwinpcapy一起使用,这样可以轻松设置数据包捕获,使用您想要的任何选项,使用自定义过滤器,接收数据包你想要的不用大惊小怪。


scapy让事情变得更加轻松 - 尽管在Windows上启动并运行scapy可能并不容易尝试Windows scapy项目,而不是自己动手。


现在,这是你出错的地方。


我不确定为什么你在sendSock.bind电话上收到错误,但可能是因为10000在短暂的端口范围之外。在XP上,默认情况下该范围是1025-5000。有关详细信息,请参阅MSDN bind文档。但是,如果您不关心源端口是什么,您可以始终只sendto而不是bind,然后使用getsockname找出哪个端口你结束了,然后用它来bind另一个套接字。但是,如果您不选择端口,则可能无法选择主机。 (这与平台有关,但我非常确定在Windows XP上,您只能使用非INADDR_ANY主机和端口0用于TCP,而不是UDP。)


在Windows上,如果两个活动套接字都绑定到同一个地址(直接或间接,例如通过一个绑定到0.0.0.0:10000而另一个绑定到192.168.1.123:10000),则内核将数据包传送到两个插座中的一个任意且不确定。有关详细信息,请参阅MSDN文章Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE。尽管这些文档说的是,但对于原始套接字来说,这并不完全正确。但是,至少在某些Windows版本上,它部分是真的。


协议为IPPROTO_RAW的Windows原始套接字根本不会收到任何内容。如果协议匹配,Windows仅将数据包传递到原始套接字,因此IPPROTO_UDP数据包将不会传递到IPPROTO_RAW套接字。但是那个很容易修复 - 只需使用IPPROTO_UDP。请参阅MSDN中的TCP/IP Raw Sockets; “发送和接收操作”部分介绍了数据包的传送方式。

此外,如果绑定本地端,可能需要绑定原始套接字的远程端。您可以通过使用与UDP套接字上的connect相同的地址调用sendto来实现此目的。早期的WinSock2不需要这样做,但它可能在以后的XP服务包中(至少在默认设置下)。


这也可能会受到影响(以不可预测的方式),无论是否启用了内置Windows防火墙。把它关掉以避免这种情况。