MST

星途 面试题库

面试题:Python中Python socket模块如何实现简单的多客户端并发通信

请描述使用Python的socket模块实现一个能够同时处理多个客户端连接的简单服务器的思路,并给出关键代码片段。例如,说明如何使用`select`模块或`asyncio`库来实现并发处理。
39.7万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

使用select模块实现并发处理的思路

  1. 创建套接字:使用socket模块创建一个TCP套接字,并绑定到指定的地址和端口。
  2. 设置为非阻塞模式:将套接字设置为非阻塞模式,以便select模块能够有效地监控其状态。
  3. 初始化select对象:创建一个select对象,并将服务器套接字添加到读集合中。
  4. 进入主循环:在主循环中,使用select对象监控读集合中的套接字。当有新的连接或数据可读时,select会返回相应的套接字。
  5. 处理新连接:如果返回的是服务器套接字,表示有新的客户端连接,接受连接并将新的客户端套接字添加到读集合中。
  6. 处理客户端数据:如果返回的是客户端套接字,表示该客户端有数据可读,读取数据并进行相应处理,处理完后可选择回显数据或执行其他操作。
  7. 关闭连接:当客户端关闭连接时,从读集合中移除相应的套接字,并关闭该套接字。

关键代码片段

import socket
import select


def multi_client_server():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind(('127.0.0.1', 8888))
    server_socket.listen(5)
    server_socket.setblocking(False)

    inputs = [server_socket]

    while inputs:
        readable, writable, exceptional = select.select(inputs, [], inputs)
        for sock in readable:
            if sock is server_socket:
                client_socket, client_addr = server_socket.accept()
                client_socket.setblocking(False)
                inputs.append(client_socket)
            else:
                try:
                    data = sock.recv(1024)
                    if data:
                        sock.sendall(data)
                    else:
                        inputs.remove(sock)
                        sock.close()
                except socket.error:
                    inputs.remove(sock)
                    sock.close()

        for sock in exceptional:
            inputs.remove(sock)
            sock.close()


if __name__ == "__main__":
    multi_client_server()

使用asyncio库实现并发处理的思路

  1. 创建异步函数:定义一个异步函数来处理每个客户端连接,在函数内使用asyncio提供的异步I/O操作来读取和写入数据。
  2. 创建服务器:使用asyncio.start_server创建一个TCP服务器,并指定处理客户端连接的异步函数。
  3. 运行事件循环:获取asyncio的事件循环,并将服务器添加到事件循环中运行,事件循环会自动调度处理每个客户端连接的异步任务。

关键代码片段

import asyncio


async def handle_connection(reader, writer):
    while True:
        data = await reader.read(1024)
        if not data:
            break
        writer.write(data)
        await writer.drain()
    writer.close()


async def start_server():
    server = await asyncio.start_server(handle_connection, '127.0.0.1', 8888)
    async with server:
        await server.serve_forever()


if __name__ == "__main__":
    asyncio.run(start_server())