我正在使用Python脚本将UDP数据包发送到服务器,该服务器将注册我的脚本以接收来自服务器的通知.该协议要求我发送自己的IP地址和端口,我希望收到这些通知,因此这应该是可以从服务器网络访问的地址.
解决方案至少应该适用于Windows XP及更高版本,最好是Mac OS X,因为这是我的开发平台.
第一步是获取任何接口的IP地址.我目前正在使用通常建议的解析机器自己的主机名的方法:
def get_local_address():
return socket.gethostbyname(socket.gethostname())
Run Code Online (Sandbox Code Playgroud)
这有时只能起作用.目前它返回172.16.249.1,这是VM Ware使用的虚拟接口的地址,所以这是一个问题.
更好的方法是获取默认接口的IP地址,这在大多数时候应该是正确的.
更好的方法是通过面向连接的协议(如TCP)获取用于连接服务器的实际IP地址.我实际上可以获得该地址,但不是在没有尝试打开连接的情况下:
def get_address_to_connect_to(server_addr):
non_open_port = 50000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((server_addr, non_open_port))
except socket.error:
pass
else:
s.close() # just in case
return s.getsockname()[0]
Run Code Online (Sandbox Code Playgroud)
在服务器无法访问或其间的恶意防火墙阻止ICMP数据包的情况下,这将阻止直到达到某个TCP超时.有没有更好的方法来获取这些信息?
DNS*_*DNS 12
我不得不一次解决同样的问题,并花了相当多的时间试图找到一个更好的方法,但没有成功.我也开始使用gethostname,但是你发现它并不总是返回正确的结果,甚至可以在hosts文件出现问题的情况下抛出异常.
我能找到的唯一可以跨平台可靠运行的解决方案是尝试连接,就像你正在做的那样.您的代码的一个改进是使用UDP而不是TCP,即SOCK_DGRAM而不是SOCK_STREAM.这避免了连接超时,并且该功能立即完成.
如果要将此代码部署到可能正在运行防火墙的客户端位置,请确保记录它执行此检查的事实.否则,他们可能会看到针对端口50000的出站连接的防火墙警告,不了解其目的,并将其视为错误.
编辑:这里大致是我使用的代码:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((host, 9))
client = s.getsockname()[0]
except socket.error:
client = "Unknown IP"
finally:
del s
return client
Run Code Online (Sandbox Code Playgroud)
我认为你得到的是0.0.0.0,因为你在调用getsockname之前关闭套接字.另一个提示是我使用端口9; 它是RFC863 UDP丢弃端口,因此比一些随机高编号端口略微怪异.
| 归档时间: |
|
| 查看次数: |
10287 次 |
| 最近记录: |