Python 确切地说,什么被传递为;地址;在ipv6的sendto中
我试图以root用户身份(Linux上的python 2.7)发送一个icmpv6 ping数据包 我知道,在ipv4的情况下,sendto使用了两元组结构(它可以工作),并且知道ipv6使用了四元组结构。我还是不能让它工作 它会导致“无效参数”或“socket.gairro:[Errno-2]名称或服务未知” 下面是一个简单的示例,显示了我的尝试。如果我能让它在ipv6的情况下与本地主机一起工作,我甚至可以:1Python 确切地说,什么被传递为;地址;在ipv6的sendto中,python,sockets,ipv6,icmp,sendto,Python,Sockets,Ipv6,Icmp,Sendto,我试图以root用户身份(Linux上的python 2.7)发送一个icmpv6 ping数据包 我知道,在ipv4的情况下,sendto使用了两元组结构(它可以工作),并且知道ipv6使用了四元组结构。我还是不能让它工作 它会导致“无效参数”或“socket.gairro:[Errno-2]名称或服务未知” 下面是一个简单的示例,显示了我的尝试。如果我能让它在ipv6的情况下与本地主机一起工作,我甚至可以:1 import socket def main(dest_name): #
import socket
def main(dest_name):
#dest_addr = socket.gethostbyname(dest_name)
addrs = socket.getaddrinfo(dest_name, 0, socket.AF_INET6, 0, socket.SOL_IP)
print addrs
dest = addrs[2]
port = 33434 # just some random number because of icmp
icmp = socket.getprotobyname('ipv6-icmp')
#print icmp
send_socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW, icmp)
print "sent to " + str(dest[4])
send_socket.sendto('', (str(dest[4]), port))
send_socket.close()
if __name__ == '__main__':
main('ipv6.google.com')
实际上,我尝试了addr列表中的每个元组,但结果是一样的
更新:
还尝试使用sendto的参数替换,但无论我使用本地主机还是google ipv6地址,都会导致无效参数
send_socket.sendto('', dest[4])
更新2:
作为参考,工作ipv4代码如下(如注释中所述)
更新3:
当我以dest[4]作为唯一参数(没有字符串,只有元组和端口)运行v6版本时,下面是我的机器(Mint 15)上的输出,其中包括打印接口
sudo python test_v6.py
[(10, 1, 6, '', ('::1', 0, 0, 0)), (10, 2, 17, '', ('::1', 0, 0, 0)), (10, 3, 0, '', ('::1', 0, 0, 0))]
sent to ('::1', 0, 0, 0)
Traceback (most recent call last):
File "test_v6.py", line 18, in <module>
main('::1')
File "test_v6.py", line 14, in main
send_socket.sendto('', dest[4])
socket.error: [Errno 22] Invalid argument
sudopython测试_v6.py
[(10, 1, 6, '', ('::1', 0, 0, 0)), (10, 2, 17, '', ('::1', 0, 0, 0)), (10, 3, 0, '', ('::1', 0, 0, 0))]
已发送到('::1',0,0,0)
回溯(最近一次呼叫最后一次):
文件“test_v6.py”,第18行,在
main('::1')
文件“test_v6.py”,第14行,在main中
send_socket.sendto(“”,dest[4])
socket.error:[Errno 22]参数无效
我不知道为什么它仍然会产生无效的参数您要寻找的所有答案几乎都在列表中 首先,端口号是
getaddrinfo
返回的信息的一部分。可以这样称呼:
def main(dest_name):
# A minimal ICMP6-echo message (thanks to abarnert)
data = '\x80\0\0\0\0\0\0\0'
# Parameters for getaddrinfo
req_port = 0
req_family = socket.AF_INET6
req_socktype = socket.SOCK_RAW
req_proto = socket.getprotobyname('ipv6-icmp')
# Resolve the name and get the addrinfo
addrs = socket.getaddrinfo(dest_name, req_port, req_family, req_socktype, req_proto)
# This gives me: [(30, 3, 58, '', ('2a00:1450:4013:c01::63', 0, 0, 0))]
# Which is what you use in your calls to `socket` and `sendto`, like:
success = False
for addr in addrs:
try:
(family, socktype, proto, canonname, sockaddr) = addr
send_socket = socket.socket(family, socktype, proto)
sent = send_socket.sendto(data, sockaddr)
send_socket.close()
except socket.error:
# Try the next address
continue
# Stop if it worked
if sent == len(data):
success = True
break
return success
现在运行main('ipv6.google.com')
时,您可以使用tcpdump
查看ping和回复:
01:14:46.763160 IP6 2a00:8640::5ce4 > 2a00:1450:4013:c01::63: ICMP6, echo request, seq 0, length 8
01:14:46.785060 IP6 2a00:1450:4013:c01::63 > 2a00:8640::5ce4: ICMP6, echo reply, seq 0, length 8
您最初的问题是,奇怪的事情,例如第一个成员是4元组地址的Python字符串表示的2元组,甚至不接近于指定地址的有效方法 您只需使用
dest[4]
本身,即作为getaddrinfo
-的sockaddr部分返回的元组作为地址,就可以解决这个问题。(正如Sander Steffann的回答所解释的那样,您并没有完全清楚地做到这一点。但在您的情况下,至少对于':1'
或'localhost'
以及您指定的其他值,您将获得正确的值来使用。)您也可能应该使用addrs[0]
而不是addrs[2]
无论如何,在您的更新3中,您似乎完全做到了这一点,并且您得到的是socket.error:[Errno 22]无效参数
。但是,sendto
有两个参数,另一个参数无效:'
不是有效的ICMP6数据包,因为它没有ICMP6头
您可以很容易地测试这一点,方法是首先将连接到dest[4]
,这将成功,然后执行一个普通的发送
,这将失败并出现相同的错误
出于某种原因,在Fedora10(古代linux)上,调用似乎无论如何都会成功。我不知道电线上到底出了什么(如果有的话)。但是在Ubuntu13.10(当前的linux)上,它在EINVAL
上失败了,这正是它应该做的。在OSX10.7.5和10.9.0上,它在ENOBUFS上失败,这很奇怪。在这三种情况下,如果我将sendto
分为connect
和send
,则失败的是send
'\x80\0\0\0\0\0\0\0'
是有效的ICMP6数据包(无数据的回显服务请求标头)。如果我用它代替你的空字符串,它现在可以在所有四台机器上工作
(当然,当我尝试在Internet上点击某个东西时,我仍然会收到ENETUNREACH
或EHOSTUNREACH
,因为我没有IPv6可路由连接。)你能显示你的IPv4代码吗?我不知道为什么您希望str(dest[4])
与IPv6的4元组一起工作,而与IPv4的2元组不一起工作。无论哪种方式,这都会创建Python元组的字符串表示形式,看起来与sendto
想要的完全不同。同时,请显示您得到的实际异常。当我使用dest[4]
(先使用或不使用dest[4][1]=port
)尝试这段代码时,它对本地主机地址成功,并为Google返回一个enetureach
错误(这是有意义的,因为我没有IPv6 internet连接)。最后,你能将IPv6 TCP连接到Google吗?你能从shell中traceroute6
或ping6
它们吗?感谢@abarnert,添加了ipv4代码我第一次将dest[4]转换为string,错误是“函数需要字符串或缓冲区,而不是元组”。我后来才意识到,这是因为我不必要地附加了另一个参数“port”。这都是真的,但如果你看他的代码,如果他只是将sendto
行修复为使用send_socket.sendto('',dest[4])
,正如我在一篇评论中所建议的,正如他所说的,他已经做到了(参见他问题中的更新和更新3)。所以,这不可能解决他的问题。谢谢,你是对的。只是想教人们如何正确地编写网络代码:-)我完全忘记在我的示例中指定数据
,作为一个简单的工作示例,它实际上可能是'\x80\0\0\0\0'
。固定的!数据部分在这里并不重要。十多年来,我一直在为网络处理器和许多其他网络堆栈编写代码,恕我直言,我不太明白这里要教什么。的确,我主要是用c编写代码的,而且我对python还不熟悉。在上面给出的例子中,我实际上使用了数据[4],它就是sock_addr结构,没有任何改进。在我的实际代码中,我也在构建ip头
01:14:46.763160 IP6 2a00:8640::5ce4 > 2a00:1450:4013:c01::63: ICMP6, echo request, seq 0, length 8
01:14:46.785060 IP6 2a00:1450:4013:c01::63 > 2a00:8640::5ce4: ICMP6, echo reply, seq 0, length 8