-
I've been having super weird issues with closing up an AnyIO socket, no matter what I do. It doesn't want me to receive any more data, I can't send, and when I try to close the socket I get an error ¯_(ツ)_/¯ Here is the socket code: import json
import random
import socket
import ssl
from sys import platform
from time import sleep
import certifi
from wsproto.events import AcceptConnection, Request, TextMessage, CloseConnection
from wsproto import WSConnection, ConnectionType
TOKEN = ... # IMPORTANT: Replace this
RECV_SIZE = 65536
SERVER_NAME = 'gateway.discord.gg'
SERVER_PORT = 443
def receive_event(ws, connection):
while True:
data = connection.recv(RECV_SIZE)
assert data # We should've gotten data (not empty)
ws.receive_data(data)
for event in ws.events():
if not isinstance(event, TextMessage):
# We don't really care about any other event
continue
return json.loads(event.data)
# Configure TLS context for WebSocket *Secure*
ctx = ssl.create_default_context(cafile=certifi.where())
# Open the underlying socket
sock = socket.create_connection((SERVER_NAME, SERVER_PORT))
sock = ctx.wrap_socket(sock, server_hostname=SERVER_NAME)
# WSProto handles the actual WebSocket connection for us
conn = WSConnection(ConnectionType.CLIENT)
sock.send(conn.send(Request(SERVER_NAME, target='/?v=9&encoding=json')))
# Receive until we get the acceptance of the connection
acceptance = None
while acceptance is not None:
conn.receive_data(sock.recv(RECV_SIZE))
for acceptance in conn.events():
assert isinstance(acceptance, AcceptConnection)
break
# Receive the HELLO event
hello = receive_event(conn, sock)
print(hello)
# Send the IDENTIFY command
sock.send(conn.send(TextMessage(
json.dumps({
'op': 2,
'd': {
'token': TOKEN,
'intents': 0,
'properties': {
'$os': platform,
'$browser': 'Testing',
'$device': 'Testing'
}
}})
)))
# We should now be receiving the READY event
ready = receive_event(conn, sock)
print(ready)
# After this, because we don't HEARTBEAT and IDENTIFied with no intents, we
# should be getting no more events. Discord will eventually disconnect us
# after roughly a minute, this is the bug-part.
event = None
while event is None:
conn.receive_data(sock.recv(RECV_SIZE))
for event in conn.events():
assert isinstance(event, CloseConnection)
# In the WebSocket protocol a closure requires both sides to respond
# to the closure.
sock.send(conn.send(event.response()))
break
# We have responded to the WebSocket close frame, we now need to shut down
# the socket
print('Closing connection')
sock.shutdown(socket.SHUT_WR)
sock.close() But then when I try to migrate to AnyIO, like this: import anyio
import json
import random
import ssl
from sys import platform
from time import sleep
import certifi
from wsproto.events import AcceptConnection, Request, TextMessage, CloseConnection
from wsproto import WSConnection, ConnectionType
TOKEN = ... # IMPORTANT: Replace this
RECV_SIZE = 65536
SERVER_NAME = 'gateway.discord.gg'
SERVER_PORT = 443
async def receive_event(ws, connection):
while True:
data = await connection.receive(RECV_SIZE)
assert data # We should've gotten data (not empty)
ws.receive_data(data)
for event in ws.events():
if not isinstance(event, TextMessage):
# We don't really care about any other event
continue
return json.loads(event.data)
sock = await anyio.connect_tcp(SERVER_NAME, SERVER_PORT, tls=True)
# WSProto handles the actual WebSocket connection for us
conn = WSConnection(ConnectionType.CLIENT)
await sock.send(conn.send(Request(SERVER_NAME, target='/?v=9&encoding=json')))
# Receive until we get the acceptance of the connection
acceptance = None
while acceptance is not None:
conn.receive_data(await sock.receive(RECV_SIZE))
for acceptance in conn.events():
assert isinstance(acceptance, AcceptConnection)
break
# Receive the HELLO event
hello = await receive_event(conn, sock)
print(hello)
# Send the IDENTIFY command
await sock.send(conn.send(TextMessage(
json.dumps({
'op': 2,
'd': {
'token': TOKEN,
'intents': 0,
'properties': {
'$os': platform,
'$browser': 'Testing',
'$device': 'Testing'
}
}})
)))
# We should now be receiving the READY event
ready = await receive_event(conn, sock)
print(ready)
# After this, because we don't HEARTBEAT and IDENTIFied with no intents, we
# should be getting no more events. Discord will eventually disconnect us
# after roughly a minute, this is the bug-part.
event = None
while event is None:
conn.receive_data(await sock.receive(RECV_SIZE))
for event in conn.events():
assert isinstance(event, CloseConnection)
# In the WebSocket protocol a closure requires both sides to respond
# to the closure.
await sock.send(conn.send(event.response()))
break
# We have responded to the WebSocket close frame, we now need to shut down
# the socket
await sock.aclose() I now get the following error: ---------------------------------------------------------------------------
SSLSyscallError Traceback (most recent call last)
~\AppData\Local\Programs\Python\Python39\lib\site-packages\anyio\streams\tls.py in _call_sslobject_method(self, func, *args)
101 try:
--> 102 result = func(*args)
103 except ssl.SSLWantReadError:
~\AppData\Local\Programs\Python\Python39\lib\ssl.py in unwrap(self)
947 """Start the SSL shutdown handshake."""
--> 948 return self._sslobj.shutdown()
949
SSLSyscallError: Some I/O error occurred (_ssl.c:2756)
The above exception was the direct cause of the following exception:
BrokenResourceError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_15900/2276960278.py in <module>
84 # We have responded to the WebSocket close frame, we now need to shut down
85 # the socket
---> 86 await sock.aclose()
~\AppData\Local\Programs\Python\Python39\lib\site-packages\anyio\streams\tls.py in aclose(self)
142 if self.standard_compatible:
143 try:
--> 144 await self.unwrap()
145 except BaseException:
146 await aclose_forcefully(self.transport_stream)
~\AppData\Local\Programs\Python\Python39\lib\site-packages\anyio\streams\tls.py in unwrap(self)
134
135 """
--> 136 await self._call_sslobject_method(self._ssl_object.unwrap)
137 self._read_bio.write_eof()
138 self._write_bio.write_eof()
~\AppData\Local\Programs\Python\Python39\lib\site-packages\anyio\streams\tls.py in _call_sslobject_method(self, func, *args)
119 await self.transport_stream.send(self._write_bio.read())
120 except (ssl.SSLEOFError, ssl.SSLSyscallError) as exc:
--> 121 raise BrokenResourceError from exc
122 else:
123 # Flush any pending writes first
BrokenResourceError: This is just a simple reproduceable of my real code on GitHub. |
Beta Was this translation helpful? Give feedback.
Answered by
agronholm
Nov 1, 2021
Replies: 1 comment
-
HTTP connections need |
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
Bluenix2
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
HTTP connections need
tls_standard_compatible=False
because such servers abruptly close the connection without performing the closing handshake.