0

我使用的眼动追踪应用程序利用 UDP 发送数据包。我在同一台计算机上制作了一个 python 套接字来监听数据并将其转储到 .txt 文件中。我已经有这么多工作了。

一个单独的应用程序也是用 python 编写的(眼动追踪的对象看到的)正在单独的计算机上运行。因为眼动追踪应用程序是连续的并且会发送不必要的数据,所以到目前为止,我不得不手动解析出对象正在查看所需刺激时的实例。我是根据刺激和眼动追踪应用程序的手动同步启动然后挖掘日志文件来做到这一点的。

我想要做的是让第二台计算机充当第二个 UDP 客户端,每次受试者查看刺激物时(之前将标记插入到 .txt 文件中),都会向眼动追踪计算机上的套接字发送一个数据包提及)。是否可以让一个套接字同时监听两个 IP 地址?

这是我的套接字脚本:

#GT Pocket client program

import datetime
import socket
now = datetime.datetime.now()
filename = 'C:\gazelog_' + now.strftime("%Y_%m_%d_%H_%M") + '.txt'

UDP_IP = '127.0.0.1' # The remote host (in this case our local computer)
UDP_PORT = 6666 # The same port as used by the GT server by default

sock = socket.socket(socket.AF_INET, #internet
                                socket.SOCK_DGRAM) #UDP 

sock.bind( (UDP_IP, UDP_PORT) )

while True:
    data, addr = sock.recvfrom( 1024) #I assume buffer size is 1024 bytes.
    print "Received Message:", data
    with open(filename, "a") as myfile:
    myfile.write(str(data + "\n"))

sock.close()
myfile.close()

编辑:

@abarnert我能够绑定到以太网接口上的主机地址并将消息从计算机B发送到计算机A,但是计算机A不再能够从自身接收数据包。当我指定UDP_IP = '0.0.0.0'计算机 B 不再能够通过以太网发送数据时。当我指定UDP_IP = ''我收到`error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

这与我在计算机 B 上用于发送数据的脚本有关:

import socket

UDP_IP = "169.254.35.231" # this was the host address I was able to send through.
UDP_PORT = 6666
MESSAGE = "Start"

print ("UDP target IP:"), UDP_IP
print ("UDP target port:"), UDP_PORT
print ("message:"), MESSAGE

sock = socket.socket(socket.AF_INET,
                 socket.SOCK_DGRAM) 
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT) )

我不知道在哪里(或根本不知道)我需要指定 INADDR_ANY,所以我没有。但我确实尝试过一次import socket.INADDR_ANY但得到了ImportError: No module named INADDR_ANY

根据您的回复,这似乎是一个简单的问题,所以我不确定我在哪里搞砸了。

EDIT2:我只是再次重读您的答案并理解为什么 socket.INADDR_ANY 不起作用。请忽略我之前编辑的那部分

EDIT3:好的,所以我在指定主机 IP 时没有获取数据的原因是我在计算机 A 上收集数据的应用程序仍被指定为发送到 127.0.0.1。所以我想通了。我仍然很好奇为什么 0.0.0.0 不起作用!

4

2 回答 2

2

不可以。一个套接字一次只能绑定到一个地址。*

如果碰巧有一个地址可以处理您想要的两件事,您可以使用单个套接字来监听它。在这种情况下,主机INADDR_ANY0.0.0.0即使没有预先存在的地址可以满足您的需求,您也可以通过例如 ipfilter 类型的接口进行设置。

但除此之外,您必须创建两个套接字。这意味着您需要使用类似的东西进行多路复用select,或者创建两个线程。


在您的情况下,您希望指定一个主机,它可以同时监听本地机器和同一以太网网络上的另一台机器。您可以在以太网接口上获取您的主机地址并绑定它。(您的机器可以在其任何接口上与自己通信。)通常,在“默认接口”上获取您的地址也适用于此 - 您会socket.gethostname()在某些地方看到绑定到的代码,例如Python Socket Programming HOWTO . 但是绑定到INADDR_ANY要简单得多。除非您想确保某些接口上的机器无法连接到您(这通常只有在您正在构建一个打算在防火墙的 DMZ 上运行的服务器时才会出现问题),否则您通常会想要使用INADDR_ANY.


最后,你如何绑定到INADDR_ANY?简短的回答是:只需使用UDP_IP = '',或者UDP_IP = '0.0.0.0'如果您想更明确。任何了解套接字的人,即使他们不了解任何 Python,也会理解'0.0.0.0'服务器代码中的含义。(您可能想知道为什么 Python 在模块中没有用于此的常量socket,尤其是在像 C 这样的低级语言时做。答案是可以,但它不是真的可用。**)


* 请注意,绑定到单个地址并不意味着您只能接收来自单个地址的数据包;这意味着您可以从可以访问该单个地址的所有网络接收数据包。例如,如果你的机器有 LAN 连接,你的地址是 10.0.0.100,和一个 WAN 连接,你的地址是 8.9.10.11,如果你绑定 10.0.0.100,你可以接收来自其他 LAN 客户端的数据包,如 10.0。 0.201 和 10.0.0.202。但是您无法从 9.10.11.12 等 WAN 客户端接收数据包作为 10.0.0.100。

** 在低级套接字 API 中,点分字符串地址'0.0.0.0'被转换为 32 位整数,如0. Python 有时将这些整数表示为ints,有时表示为 4 字节缓冲区,如b'\0\0\0\0'. 根据您的平台和版本,socket.INADDR_ANY常量可以是0b'\0\0\0\0'。该bind方法不会采取0,也可能不会采取b'\0\0\0\0''0.0.0.0'如果不首先检查您拥有的表单,然后在其上调用正确的函数,您就无法转换为。这很丑陋。这就是为什么它更容易使用的原因'0.0.0.0'

于 2013-11-08T21:29:24.930 回答
0

我相信您可以将原始套接字绑定到整个接口,但您似乎正在使用两个不同的接口。

最好将两个套接字与 select() 一起使用。

于 2013-11-08T21:45:14.473 回答