尝试通过 python 套接字升级到 http2
Posted
技术标签:
【中文标题】尝试通过 python 套接字升级到 http2【英文标题】:trying to upgrade to http2 via python socket 【发布时间】:2021-06-29 17:26:29 【问题描述】:我正在尝试使用 python 套接字升级到 http/2.0。我已经尝试过像这样使用升级标头:Connection: Upgrade
然后Upgrade: h2c
。这使服务器响应 http/1.1 200 OK 响应。我现在正在尝试通过 ssl
模块使用 ALPN。
这是通过 ALPN 尝试的代码:
def connect_socket(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
context = ssl.create_default_context()
context.set_alpn_protocols(['h2c'])
while True:
try:
sock.connect(("twitter.com", 443))
sock = context.wrap_socket(sock)
return sock
except:
pass
这只是挂在context.wrap_socket(sock)
。如果我摆脱上下文并只使用ssl.wrap_socket()
一切正常,我可以使用 HTTP/1.1 很好。服务器确实支持它,因为使用 PyCurl 的详细模式我可以看到它使用 HTTP/2。
我试过使用h2c
http/2.0
和h2
。
打印我得到的异常,结果是这样的:
[WinError 10056] A connect request was made on an already connected socket
仍未升级的最新代码:
def connect_socket(self):
while True:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
context = ssl.create_default_context()
context.set_alpn_protocols(['h2c'])
context.check_hostname = False
try:
sock.connect(("twitter.com", 443))
sock = context.wrap_socket(sock)
return sock
except Exception as e:
sock.close()
print(e)
这会返回一个没有错误的套接字,然后发送这个请求:
def test_send_data(self, sock):
unencoded_string = 'GET /noah HTTP/1.1\r\nHost: twitter.com\r\nConnection: keep-alive\r\n\r\n'
sock.send(unencoded_string.encode())
这发送很好,响应的重要部分是这样的:
HTTP/1.1 200 OK\r\ncache-control: no-cache, no-store, must-revalidate,
我的问题是:为什么它只是挂起,我该如何解决?
【问题讨论】:
与'h2c'
相比,'h2'
有什么改变吗?
不,事实证明我遇到了异常。详情请查看已编辑的问题。
while 循环是怎么回事?我相信你首先遇到了一个不同的异常,它传递了异常,然后当你再次连接时你会发现你已经在套接字上,因为你处于一个循环中。
哎呀,在最近的评论之前不小心删除了我的评论,后人是“将server_hostname="twitter.com"
传递给wrap_socket
并使用h2作为协议。应该没问题。摆脱while循环并且不要传递你的异常。”
事实证明你是对的。使用 h2 而不是检查主机名对我来说会挂起,但传递 server_hostname 会起作用。在那之后,我的下一个错误实际上是在我正在寻找 \r\n\r\n 以打破读取循环并返回字节字符串的 recv 函数中。我刚刚意识到这不起作用,在打印套接字接收数据后如果你愿意,发布答案,我会接受+投票。
【参考方案1】:
我认为您的一些异常处理给了您错误的提示。如果您遇到异常,您会一直在尝试再次连接,并且在某些时候 Windows 会抱怨尝试连接到未关闭的套接字。
HTTP/2 的 ALPN 协议应该设置为h2
,然后运行你的代码给我一个错误:
ValueError: check_hostname requires server_hostname
添加该参数后,我能够从服务器获得响应,Python 说连接是 H2:
import socket
import ssl
def connect_h2_socket(host):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
context = ssl.create_default_context()
context.set_alpn_protocols(["h2"])
sock.connect((host, 443))
sock = context.wrap_socket(sock, server_hostname=host)
return sock
s = connect_h2_socket("twitter.com")
print("Selected protocol:", s.selected_alpn_protocol())
print(s.recv())
运行它会为我产生以下结果:
Selected protocol: h2 b'\x00\x00\x06\x04\x00\x00\x00\x00\x00\x00\x04\x00\x01\x00\x00'
【讨论】:
你会不会碰巧知道如何通过 HPACK 解压缩响应?我似乎遇到了很多错误 @Noah 我不知道 HPACK 是什么,最好单独问一个问题!以上是关于尝试通过 python 套接字升级到 http2的主要内容,如果未能解决你的问题,请参考以下文章