【问题标题】:can python asyncio data_received receive all data which client sentpython asyncio data_received 可以接收客户端发送的所有数据吗
【发布时间】:2018-01-16 18:17:06
【问题描述】:

我正在学习 python asyncio 模块并尝试用它编写一个 socks5 服务器。 Python 文档说:

在接收到一些数据时调用。 data 是一个非空字节对象 包含传入的数据。

我想知道当客户端发送 2 个字节的数据时,data_received(self, data) 会不会在调用时只收到 1 个字节而不是 2 个字节,其余的 1 个字节会再次调用 data_received(self, data)

#!/usr/bin/env python3

import asyncio
import logging
import socket
import struct

logging.basicConfig(level=logging.DEBUG,
                    format='{asctime} {levelname} {message}',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    style='{')


class Remote(asyncio.Protocol):
    def connection_made(self, transport):
        self.transport = transport
        self.server_transport = None

    def data_received(self, data):
        self.server_transport.write(data)


class Server(asyncio.Protocol):
    INIT, REQUEST, REPLY = 0, 1, 2

    def connection_made(self, transport):
        client_info = transport.get_extra_info('peername')
        logging.info('connect from {}'.format(client_info))
        self.transport = transport
        self.state = self.INIT

    def data_received(self, data):
        if self.state == self.INIT:
            if data[0] == 5:
                amount = data[1]    # Authentication amount
                if 0 in data[2:]:
                    self.transport.write(b'\x05\x00')
                    self.state = self.REQUEST

                else:
                    self.eof_received()
            else:
                self.eof_received()

        elif self.state == self.REQUEST:
            ver, cmd, rsv, addr_type = data[:4]
            logging.info('addr type: {}'.format(addr_type))
            if addr_type == 1:    # ipv4
                addr = socket.inet_ntoa(data[4:8])

            elif addr_type == 3:
                addr_len = data[4]
                addr = data[5:5+addr_len]

            else:
                data = b'\x05\x08\x00\x01'
                data += socket.inet_aton('0.0.0.0') + struct.pack('>H', 0)
                self.transport.write(data)
                logging.error('not support addr type')
                self.eof_received()

            port = struct.unpack('>H', data[-2:])[0]
            logging.info('target: {}:{}'.format(addr, port))
            asyncio.ensure_future(self.remote(addr, port))
            self.state = self.REPLY

        elif self.state == self.REPLY:
            logging.info('start relay')
            self.remote_transport.write(data)

    async def remote(self, addr, port):
        loop = asyncio.get_event_loop()
        transport, _remote = await loop.create_connection(Remote, addr, port)
        _remote.server_transport = self.transport
        self.remote_transport = transport
        bind_addr, bind_port = transport.get_extra_info('sockname')
        data = b'\x05\x00\x00\x01'
        data += socket.inet_aton(bind_addr) + struct.pack('>H', bind_port)
        self.transport.write(data)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    server = loop.create_server(Server, '127.0.0.2', 1089)
    loop.run_until_complete(server)

    try:
        loop.run_forever()

    except KeyboardInterrupt:
        server.close()
        loop.run_until_complete(server.close())
        loop.close()

【问题讨论】:

    标签: python python-3.x asynchronous python-asyncio


    【解决方案1】:

    不,data_received 将收到与服务器已收到的字节数相同的字节数。如果您需要接收前 3 个字节来处理请求,那么您应该在您的协议中实现一些缓冲,以允许您在继续之前等待其余的请求到达。

    它通常看起来像这样:

    def __init__(self, …):
        self._buffer = bytearray()
        …
    
    def data_received(self, data):
        self._buffer += data
    
        if self.state == self.INIT:
            # here we need at least 3 bytes.
            # if we don't have enough data yet, just wait for the next `data_received` call
            if len(self._buffer) < 3:
                return
    
            header, self._buffer = self._buffer[:2], self._buffer[2:]
            # parse authentication header, switch the state to REQUEST
    
        elif self.state == self.REQUEST:
            …
    

    【讨论】:

    • 感谢您的帮助,我实现了一个 data_buf 以确保我现在收到所有数据。
    猜你喜欢
    • 1970-01-01
    • 2020-03-06
    • 2021-06-25
    • 2021-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多