我正在学习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()
答案 0 :(得分: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:
…