python实现单线程多任务非阻塞TCP服务端

Python实现单线程多任务非阻塞TCP服务端,主要采用异步非阻塞编程模型,使用Python内建的asyncio库,同时搭配使用socket、select等标准库实现。

以下是Python 实现单线程多任务非阻塞TCP服务端的攻略:

  1. 创建一个协程 async def handle_client(client_socket, client_address),用来作为TCP连接的服务器端处理逻辑。其中client_socket用来处理与客户端的通信接口,client_address为客户端的地址和端口号。

  2. 创建一个协程 async def handle_clients(),用来作为TCP服务器的监听函数,可以接收多个客户端连接请求。该函数会不断的进行accept()操作,等待客户端连接请求,一旦有请求过来,就会回调handle_client协程,客户端的连接请求将由handle_client协程来进行处理。

  3. 为了避免使用阻塞型的accept()调用,我们可以使用Python标准库中的select函数来进行多路复用,从而创建一个异步非阻塞的服务端程序。在handle_clients协程中,使用selectors模块创建Selector对象sel,用来实现多路复用IO。

  4. 在handle_clients协程中,通过调用socket的setblocking(0)方法,将socket设置为非阻塞模式,如果出现了非阻塞问题,就会抛出socket.error异常。这些异常处理在handle_client协程中都应该考虑到。

示例一:实现一个简单的Echo服务器

import asyncio
import socket

async def handle_client(client_socket, client_address):
    print(f"Connection from {client_address}")
    try:
        while True:
            data = await asyncio.to_thread(client_socket.recv, 1024)
            if not data:
                break
            await asyncio.to_thread(client_socket.sendall, data)
    except socket.error as e:
        print(f"Socket error: {e}")
    finally:
        client_socket.close()
        print(f"Connection closed from {client_address}")

async def handle_clients():
    sel = selectors.DefaultSelector()
    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", 8000))
    server_socket.setblocking(False)
    server_socket.listen(5)
    sel.register(server_socket, selectors.EVENT_READ, data=None)

    while True:
        events = await asyncio.to_thread(sel.select)
        for key, mask in events:
            if key.data is None:
                handle_accept(key.fileobj, sel)
            else:
                await asyncio.create_task(key.data.handle_client(key.fileobj, mask))

async def handle_accept(sock, mask):
    client_socket, client_address = sock.accept()
    client_socket.setblocking(False)
    await asyncio.create_task(handle_client(client_socket, client_address))

asyncio.run(handle_clients())

示例二:实现一个异步非阻塞的Web服务器

import asyncio
import sys

def get_content_type(filename):
    return {
        '.html': 'text/html',
        '.css': 'text/css',
        '.jpg': 'image/jpeg',
        '.png': 'image/png',
        '.ico': 'image/x-icon'
    }.get(filename, 'application/octet-stream')

async def handle_read(client_socket, request):
    try:
        while True:
            data = await asyncio.to_thread(client_socket.recv, 1024)
            request += data.decode('utf-8')
            if '\r\n\r\n' in request:
                break
    except socket.error as e:
        print(f"Error: {e}")
    return request.strip()

async def handle_write(client_socket, response):
    try:
        await asyncio.to_thread(client_socket.sendall, response.encode('utf-8'))
    finally:
        client_socket.close()

async def handle_request(client_socket, client_addr):
    request = await asyncio.create_task(handle_read(client_socket, ""))
    filename = re.match(r'GET /(\S+)\s+', request).group(1)
    filename = '.' + filename if filename != '/' else './index.html'
    try:
        with open(filename, 'rb') as f:
            content = f.read()
            content_type = get_content_type(filename)
            response = f'HTTP/1.1 200 OK\r\nContent-Type: {content_type}\r\nContent-Length: {len(content)}\r\n\r\n{content.decode("utf-8")}'
    except FileNotFoundError:
        response = 'HTTP/1.1 404 NOT FOUND\r\nContent-Type: text/html\r\n\r\n<html><body><h1>404 Not Found!</h1></body></html>'

    await asyncio.create_task(handle_write(client_socket, response))

async def handle_clients():
    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', 8001))
    server_socket.setblocking(False)
    server_socket.listen(5)

    while True:
        try:
            client_socket, client_address = server_socket.accept()
            client_socket.setblocking(False)
        except socket.error as e:
            print(f"Error: {e}")
            continue
        await asyncio.create_task(handle_request(client_socket, client_address))

asyncio.run(handle_clients())

以上示例可以用于学习Python单线程多任务非阻塞TCP服务端的核心思路和编程实现。实际使用中应将性能等因素进行详细考虑,进行相应的优化和调整。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python实现单线程多任务非阻塞TCP服务端 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • c#可以创建任意控件的拖动方法

    标准的拖放流程 首先,需要在窗体上放置一个容器控件,比如Panel或者GroupBox,在这个容器控件上,就可以进行拖放了,具体的代码流程如下: private void panel1_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(typeof(Button))) …

    other 2023年6月26日
    00
  • layui—表单验证

    以下是关于“layui—表单验证”的完整攻略,包括基本概念、步骤和两个示例说明。 基本概念 Layui是一款轻量的前端UI框架,它提供了丰富的组件和工具,可以帮助我们快速构建美观、易用的Web界面。其中,表单验证是Layui框架的一个重要功能,可以帮助我们验证用户输入的数据是否符合要求。 步骤 以下是使用Layui进行表单验证的步: 引Layui框架:在…

    other 2023年5月7日
    00
  • Oracle 查询表信息获取表字段及字段注释

    获取表字段及字段注释是在进行数据库开发时非常常见的需求,Oracle提供了一些SQL命令可以快速查询到表字段信息及注释。下面将详细讲解如何使用Oracle查询表信息获取表字段及字段注释的完整攻略。 1. 查询表字段信息 简介 查询表字段信息就是查询某个表的所有字段名、数据类型、长度等信息。 SQL命令 DESC table_name; 示例 假设有一个名为u…

    other 2023年6月25日
    00
  • cv2.imshow同时显示两张图片

    cv2.imshow同时显示两张图片 在使用OpenCV进行图像处理时,我们通常需要显示图像以便于观察处理的效果。OpenCV提供了一个imshow函数来实现图像的显示。当需要显示多张图像时,我们可以使用cv2.imshow函数同时显示多张图像。本文介绍如何使用cv2.imshow同时显示两张图片。 准备工作 在进行本文中的代码操作前,需要安装OpenCV库…

    其他 2023年3月28日
    00
  • Android中Service服务详解(二)

    Android中Service服务详解(二) 在Android开发中,Service是一种可以在后台执行长时间运行操作的组件。本文将详细讲解Android中Service服务的使用方法和注意事项。 1. Service的基本概念 Service是一种在后台执行操作的组件,它没有用户界面。Service可以在后台运行,即使用户切换到其他应用程序,Service…

    other 2023年9月7日
    00
  • 网页WEB打印控件制作

    网页WEB打印控件制作攻略 概述 网页WEB打印控件是一种能够帮助网站用户方便地将网页内容打印出来的工具。它能够使网页内容按照用户需求进行自定义排版、缩放、纸张大小和方向等设置,同时还能自动去除无用元素,从而帮助用户简洁高效地打印出自己需要的网页内容。 制作步骤 下面是一个基本的网页WEB打印控件的制作步骤: 创建一个页面,添加打印控件 在页面中添加以下代码…

    other 2023年6月26日
    00
  • ASP、PHP与javascript根据时段自动切换CSS皮肤的代码

    实现网站根据时段自动切换CSS皮肤的代码需要用到服务器端的脚本语言,如ASP、PHP等,以及客户端的脚本语言JavaScript。下面是具体的实现流程: 创建多个CSS皮肤 要实现时段自动切换CSS皮肤,首先需要创建多个CSS皮肤。可以根据自己的需求和设计风格,创建不同的CSS文件,例如“皮肤1.css”、“皮肤2.css”等。 创建切换皮肤的脚本 在网站中…

    other 2023年6月27日
    00
  • 基于MySQL的存储引擎与日志说明(全面讲解)

    基于MySQL的存储引擎与日志说明 存储引擎 MySQL是一种关系型数据库管理系统,其数据存储的方式是通过存储引擎实现的,MySQL支持多种不同的存储引擎,每种存储引擎都具有不同的特性和优势。下面介绍一些常用的MySQL存储引擎。 InnoDB InnoDB是MySQL官方推荐的默认存储引擎,具有ACID事务支持和行级锁定的特性。它适用于高并发的OLTP(在…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部