python-websockets / websockets

Library for building WebSocket servers and clients in Python
https://websockets.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
5.06k stars 505 forks source link

events_received does not return any events after sending them to receive_data #1431

Closed niceguy135 closed 5 months ago

niceguy135 commented 5 months ago

Hello, everyone! I`am using:

I am trying to integrate the Sans-I/O websockets layer into my application. Its essence is that data in the SPICE protocol will be transmitted over WebSockets. I use the Sans-I/O layer specifically, since I have to work with winsockets directly (via ctypes in python, if anyone needs it).

The problem is that the events_received command does not return any events (except for the very first Response event, which I handled earlier). And, accordingly, I cannot get the data for further work with them. Nevertheless, I am able to send data and the server successfully receives it.

Code:

    async def recv(self):
        print("Reciving data...")
        while True:
            print("recive data from sock")
            try:
                data = self.vsock.recv()
                print("Recived data: ", data)
            except OSError:  # socket closed
                print("OSError: socket maybe closed!")
                data = b""

            print("check is data empty")
            if data:
                closeFlag = False
                self.protocol.receive_data(data)
            else:
                closeFlag = True
                self.protocol.receive_eof()

            print("sending data to server")
            for datum in self.protocol.data_to_send():
                if datum:
                    self.vsock.send(datum)
                else:
                    self.vsock.shutdown(1)

            print("check, is close expected")
            if self.protocol.close_expected():
                time.sleep(3)
                self.sock.close()

            if closeFlag:
                break

        dataToRecv = b''
        events = self.protocol.events_received()
        print("Reading events")
        for frame in events:
            print(frame)
            if frame == Frames:
                if frame.opcode == Frames.Opcode.BINARY:
                    dataToRecv += frame.data

        print("Data has been recived! Total: ", len(dataToRecv))

        return dataToRecv

Result in my cmd:

Reciving data...
recive data from sock
Recived data:  b'\x82~\x00\xcaREDQ\x02\x00\x00\x00\x02\x00\x00\x00\xba\x00\x00\x00\x00\x00\x00\x000\x81\x9f0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x81\x8d\x000\x81\x89\x02\x81\x81\x00\xd1I\xd3\xcb\xbf\t\xec\xa8 \xe92\xbf\xac\xf2\x94iB:\xf9\xd26\xef\x84O?f\x93\x8e\xc7\xe0\xda\x8b\xdeM\xce\x0f\xe7\xc6A\x0c\x93\x83\xe4\xbc\xebY\xaceT\x84\x0bo9\xc1JW\xb3/\xaf\xdb2-\xd1\xd8\xc4\xeec\x99\xee*y\xd389\xa8\x18\x84:Q\xda]\x1a\x8a\x08,\r@\x19r\xe3\xf9\x00\x0f\r\x0e\xaa\xc2\x85\x02g\xee`t\xfeo\xbcc6\x16\xe3%P\x14\xb5U\x84\x0b#\xfcV\xc3\xc7\xed\xb3\x8b\xf3oS\x02\x03\x01\x00\x01\x01\x00\x00\x00\x01\x00\x00\x00\xb2\x00\x00\x00\x0b\x00\x00\x00\t'
check is data empty
sending data to server
check, is close expected
recive data from sock
Recived data:  b''
check is data empty
sending data to server
check, is close expected
Reading events
Data has been recived! Total:  0
aaugustin commented 5 months ago

Apparently the data sent by the server is 3 bytes shorter than it should be:

>>> data = b'\x82~\x00\xcaREDQ\x02\x00\x00\x00\x02\x00\x00\x00\xba\x00\x00\x00\x00\x00\x00\x000\x81\x9f0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x81\x8d\x000\x81\x89\x02\x81\x81\x00\xd1I\xd3\xcb\xbf\t\xec\xa8 \xe92\xbf\xac\xf2\x94iB:\xf9\xd26\xef\x84O?f\x93\x8e\xc7\xe0\xda\x8b\xdeM\xce\x0f\xe7\xc6A\x0c\x93\x83\xe4\xbc\xebY\xaceT\x84\x0bo9\xc1JW\xb3/\xaf\xdb2-\xd1\xd8\xc4\xeec\x99\xee*y\xd389\xa8\x18\x84:Q\xda]\x1a\x8a\x08,\r@\x19r\xe3\xf9\x00\x0f\r\x0e\xaa\xc2\x85\x02g\xee`t\xfeo\xbcc6\x16\xe3%P\x14\xb5U\x84\x0b#\xfcV\xc3\xc7\xed\xb3\x8b\xf3oS\x02\x03\x01\x00\x01\x01\x00\x00\x00\x01\x00\x00\x00\xb2\x00\x00\x00\x0b\x00\x00\x00\t'
>>>
>>> from websockets.streams import StreamReader
>>> reader = StreamReader()
>>> reader.feed_data(data)
>>> reader.feed_eof()
>>> 
>>> from websockets.frames import Frame
>>> parser = Frame.parse(reader.read_exact, mask=False)
>>>
>>> try:
...     next(parser)
... except StopIteration as exc:
...     print(exc.value)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/Users/myk/dev/websockets/src/websockets/frames.py", line 258, in parse
    data = yield from read_exact(length)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/myk/dev/websockets/src/websockets/streams.py", line 71, in read_exact
    raise EOFError(f"stream ends after {p} bytes, expected {n} bytes")
EOFError: stream ends after 199 bytes, expected 202 bytes

websockets never gets a complete frame that events_received would return.

If you add three bytes, then it works:

>>> data += b'abc'
>>> 
>>> reader = StreamReader()
>>> reader.feed_data(data)
>>> reader.feed_eof()
>>> 
>>> parser = Frame.parse(reader.read_exact, mask=False)
>>> 
>>> try:
...     next(parser)
... except StopIteration as exc:
...     print(exc.value)
...
BINARY 52 45 44 51 02 00 00 00 02 00 00 00 ba 00 00 00 ... 0b 00 00 00 09 61 62 63 [202 bytes]
aaugustin commented 5 months ago

For clarity, I'm saying that it's a bug in the server you are connecting to.

aaugustin commented 5 months ago

PS: did you try connect("ws://...", sock=vsock) where vsock is your winsocket object? If vsock behaves sufficiently like a socket, and your example suggests that it does, that should work?

niceguy135 commented 5 months ago

Yeap, the problem was related to the server. I'm sorry for the unnecessary concern and thank you