如何通过socket解析使用wss协议的主机名?
我试过这个却失败了:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = socket.gethostbyname('wss://domain.tld')
答案 0 :(得分:3)
wss://domain.tld
不是主机名,而是URL。您无法使用套接字解析URL,您必须将其解析为URL以从中获取主机名,然后您可以解决该问题。该方案是wss,http还是rsync并不重要;任何具有netloc
字段的方案都将以相同的方式工作。
例如,使用urllib.parse
:
>>> from urllib.parse import urlparse # in 2.x it's from urlparse
>>> url = 'wss://domain.tld'
>>> bits = urllib.parse.urlparse(url)
>>> netloc = bits.netloc
>>> netloc
'domain.tld'
所以我们完成了,对吧?
不。 netloc
可以是主机,也可以是主机:端口。而且你不能只是split(':')
,因为IPv6地址中可以包含冒号 - 但只有当它们被括在括号中时才会有。因此,要获得host
的{{1}}部分,您需要执行以下操作:
netloc
现在我们 已完成,我们有一个主机名或IP地址,我们可以将其传递给socket.gethostbyname
。
但有几个注意事项。
首先,您无需创建>>> host, _, port = netloc.rpartition(':')
>>> if ']' in port: host = netloc
>>> host
'domain.tld'
对象来呼叫socket.socket
;它是模块的顶级函数,不需要任何套接字对象。
其次,gethostbyname
不适用于IPv6,甚至在IPv4上也有一些限制,因此您可能希望改用getaddrinfo
。
所以,完成:
gethostbyname
嗯,这是预料之中的,因为我们的主机名是>>> import socket
>>> addresses = socket.getaddrinfo(host, None) # or host, port if you prefer
gaierror: [Errno 8] nodename nor servname provided, or not known
,并且没有这样的域名。但是,如果我们使用domain.tld
,我们会得到一个很好的列表,其中包含几十个IPv4地址,如果您的系统具有IPv6连接,那么也可以使用几个IPv6地址。您可以只使用第一个,或者更喜欢IPv4到IPv6,反之亦然,或者在某个其他字段上进行区分。 (您还可以通过向www.google.com
传递更多参数来首先过滤各种字段。)