是否可以通过不同的套接字发送和接收数据包? [英] Is it possible to send and receive packets through different sockets?

查看:391
本文介绍了是否可以通过不同的套接字发送和接收数据包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我googled了一会儿,在这里阅读了关于通过套接字发送和接收的相关问题,但找不到我的问题的答案:

I googled for a while and read related questions here about sending and receiving through sockets, but couldn't find an answer to my question:

我可以发送和

我想实现这样:

HOST='127.0.0.1'
PORT=10000
recvSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sendSock.sendto("",(HOST,PORT))
response,addr = recvSock.recvfrom(65535)

基本上,我想通过sendSock发送一个消息到echo服务器,它是UDP套接字,并从服务器接收答案通过recvSock这是一个原始的套接字。

Basically, I'd like to send a message to an echo server through sendSock which is UDP socket, and receive the answer from the server through recvSock which is a raw socket.

这是可能吗?如果是,那么如何?

Is it possible? If yes, then how? the code about doesn't work.

推荐答案

让我们备份一下,因为书面上你的问题没有什么意义,但我想我知道你想要做什么。

Let's back up a bit, because as written your question doesn't make much sense, but I think I know what you're trying to do.

当你创建一个UDP套接字并发送一个消息,它做了两件事:首先,它选择一个适当的源地址,使用任意端口从临时范围,并将你的套接字绑定到该地址。 (A UDP地址是主机IP和端口。)然后它从该源地址发送一个消息到目的地址。

When you created a UDP socket and sent a message on it, this did two things: First, it picked an appropriate source address, with an arbitrary port from the ephemeral range, and bound your socket to that address. (A UDP address is a host IP and a port.) Then it sent a message from that source address to the destination address.

当远程端响应时,发送消息到该源地址。内核接收到该消息,并看到它的目标是你的UDP套接字绑定的地址。

When the remote side responds, it will send a message to that source address. The kernel receives that message and sees that it's aimed at the address your UDP socket is bound to. So it delivers the message to that socket.

这意味着 recvfrom 只能在那个套接字上工作, 。只要在不绑定任何东西的不同套接字上调用 recvfrom 就行不通。

That means recvfrom will only work on that socket, not another one. Just calling recvfrom on a different socket that isn't bound to anything won't do any good.

如果你可以绑定两个套接字到同一个地址?那么,你可以使用套接字选项 SO_REUSEADDR 和/或 SO_REUSEPORT 。请参见此问题一些(高度平台特定)的细节,当它允许每个选项。但是,即使在允许的情况下,如果收到一个具有两个套接字的地址的消息,会发生什么?嗯,这也是高度平台特定。理论上,消息被任意地传递到其中一个套接字。实际上,在一些平台上,内核将记住最近发送到响应的源地址的人,或者与源地址相同的网络上的任何地址,或最近绑定的任何地址或某些其他规则,并且递送到一。所以,根据你的平台,这可能或可能不会帮助你,你可以绑定一个套接字,使用它 sendto ,然后绑定第二个套接字,然后 recvfrom 第二个并获得响应。或者它可能不。如果它不做你想要的,不要试图与你的内核战斗;

What if you could bind two sockets to the same address? Well, you can, by using the socket options SO_REUSEADDR and/or SO_REUSEPORT. See this question for some (highly platform-specific) details on when it's allowed with each option. But, even when it's allowed, what happens when a message is received for an address that has two sockets bound to it? Well, that's also highly platform-specific. In theory, the message is delivered to one of the sockets arbitrarily. In practice, on some platforms, the kernel will remember who most recently sent to source address of the response, or to any address on the same network as the source address, or who bound most recently, or some other rule, and deliver to that one. So, depending on your platform, that may or may not help you—you may be able to bind one socket, use it to sendto, then bind the second socket, then recvfrom on the second and get the response. Or it may not. And if it doesn't do what you want, don't try to fight with your kernel; there are better ways to go if you want to get under the covers.

如果你绑定到一个更包容的地址,该怎么办?例如,您可以将第一个套接字绑定到('127.0.0.1',12345),然后将第二个绑定到('0.0.0.0' ,12345),那些是不同的地址,对不对?好吧,这基本上解释类似于将它们绑定到相同的套接字 - 平台特定的差异在上面链接的同一个答案解释,如果你被允许这样做的行为将是相同的,如果你使用相同的地址。在大多数平台上,即使你将一个(原始)套接字绑定到一个接口而不是一个地址,也是如此。

What if you bind to a more inclusive address? For example, you could bind the first socket to ('127.0.0.1', 12345) and then bind the second to ('0.0.0.0', 12345), and those are different addresses, right? Well, that's basically interpreted similarly to binding them both to the same sockets—the platform-specific differences are explained in the same answer I linked above, and the behavior if you're allowed to do it will be the same as if you'd used the same address. And on most platforms, this is true even if you bind a (raw) socket to an interface rather than an address.

甚至不能接收UDP(或TCP)数据包。除非你构建一个包过滤器重新路由它们,它们总是由内核处理,并传递到UDP或TCP套接字(或防火墙,如果没有)。 原始IP网络常见问题解释了您可以并且不能根据最初定义的BSD原始套接字协议进行接收。幸运的是,大多数现代平台超越了原来的BSD套接字协议 - 不幸的是,他们都以不同的方式做。

On top of this, classic BSD raw sockets can't even receive UDP (or TCP) packets. Unless you build a packet filter to reroute them, they're always handled by the kernel and delivered to a UDP or TCP socket (or to the firewall, if there is none). The Raw IP Networking FAQ explains exactly what you can and can't receive according to the BSD raw socket protocol as originally defined. Fortunately, most modern platforms go beyond the original BSD socket protocol—unfortunately, they all do so in different ways.

你可以解决这两个问题, 模式,这意味着它将在路由之前在其接口上获取所有数据包。 (在每个平台上,这样做的方式也不同。)由你来决定哪些将被路由到你的UDP套接字并适当地处理它们。 (这对于UDP来说并不是太难;对于TCP它变得更复杂,因为TCP数据包在被传递到套接字之前被存储和重新排序)。

You can solve both of these problems by putting the socket into promiscuous mode, which means it will get all packets on its interface before they get routed. (The way to do this is also different on each platform.) It's up to you to then figure out which ones are going to get routed to your UDP socket and process them appropriately. (This isn't too hard with UDP; with TCP it gets more complicated because of the fact that TCP packets are stored and put back in order before being delivered to the socket.)

一个更简单的解决方案是使用您平台的包过滤器接口。

An easier solution is to use your platform's packet filter interface.

或者,更容易使用 libpcap

Or, even easier, use something like libpcap, which has cross-platform wrappers for packet capturing.

或者,更容易使用 scapy ,它有 libpcap 和所有其他必要的Python包装器,或 wireshark ,一个单独的程序,可以从Python自动化。这样,它很容易捕获将被发送到你的套接字的数据包,并解析头和一切你想做的事情。

Or, even easier, use something like scapy, which has Python wrappers around libpcap and everything else necessary, or wireshark, a separate program which you can automate from Python. Going this way makes it trivial to capture exactly the packets that will be delivered to your socket and parse the headers and everything else you want to do.

或者,一些平台提供一种方法来获取UDP套接字上的所有数据包上的头。这需要使用 recvmsg 而不是 recvfrom ,因为标题作为辅助数据提供,而不是作为主接收缓冲区。 Python 3.3有 recvmsg ;早期版本没有,你必须使用 ctypes 或一些第三方包装器(或构建自己的包装器)。

Or, some platforms provide a way to get the headers on all packets on UDP sockets. This requires using recvmsg instead of recvfrom, because the headers are delivered as "ancillary data" rather than as part of the main receive buffer. Python 3.3 has recvmsg; earlier versions do not, and you will have to use ctypes or some third-party wrapper (or build your own wrapper).

这篇关于是否可以通过不同的套接字发送和接收数据包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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