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日

相关文章

  • MySQL大表中重复字段的高效率查询方法

    针对MySQL大表中重复字段的高效率查询,常见的解决方法包括使用索引或者分库分表等方式,下面我将详细讲解这方面的攻略。 索引优化 使用索引是提高MySQL查询效率的常用方法,对于大表中的重复字段尤其有效。在使用索引时,我们需要注意如下几点: 对于经常查询的字段,建议使用单独的索引,避免创建复合索引。 对于varchar类型的字段,建议指定长度。例如,如果某字…

    other 2023年6月25日
    00
  • 使用sevenzipsharp压缩/解压7z格式

    以下是使用SevenZipSharp压缩/解压7z格式的完整攻略,包含两个示例说明: 步骤1:安装SevenZipSharp 首先,需要安装SevenZipSharp。可以使用NuGet包管理器安装SevenZipSharp。以下是安装步骤: 打开Visual Studio。 在解决方案资源管理器中,右键单击项目,然后选择“NuGet程序包”。 在NuGet…

    other 2023年5月9日
    00
  • openssl下载安装

    以下是关于如何下载安装OpenSSL的完整攻略: 1. 下载OpenSSL 可以从OpenSSL官方网站(https://www.openssl.org/)下载OpenSSL。在下载页面中,可以选择下载最新版本或旧版本的OpenSSL。选择适合自己的版本后,可以下载对应的压缩包。 例如,下载OpenSSL 1.1.1版本的压缩包,可以使用以下命令: wget…

    other 2023年5月8日
    00
  • vim recording

    下面是“vim recording的完整攻略”,包括基本原理、实现方法和两个示例说明。 基本原理 在 Vim 中,可以使用录制功能来记录一系列的编辑操作,然后将其保存为宏以便重复使用。录制功能可以帮助用户快速、高效地完成重复性的编辑任务。 实现方法 实现录制功能可以按照以下步骤进行操作: 打开 Vim 编辑器。 按下“q”键,然后输入一个字母来指定宏的名称。…

    other 2023年5月5日
    00
  • Android集成腾讯X5实现文档浏览功能

    Android集成腾讯X5实现文档浏览功能 步骤一:导入腾讯X5库 首先,您需要在项目的build.gradle文件中添加腾讯X5库的依赖。在dependencies块中添加以下代码: implementation ‘com.tencent.tbs.tbssdk:sdk:43959’ 步骤二:配置AndroidManifest.xml文件 在AndroidM…

    other 2023年10月14日
    00
  • Vue中图片上传组件封装-antd的a-upload二次封装的实例

    一、背景 在Vue项目中,我们经常会使用上传图片的功能,而Ant Design Vue提供了一个非常方便的组件——a-upload,但是它的样式和功能可能无法满足我们的需求。因此,我们需要对它进行二次封装,定制我们需要的功能和样式。 二、封装步骤 创建一个Upload组件,在里面引入a-upload组件。 <template> <a-upl…

    other 2023年6月25日
    00
  • php中laravel调度执行错误解决方法

    问题描述: 在使用Laravel框架开发PHP应用时,有时会出现调度执行错误。这些错误通常是由于代码中的逻辑错误或框架版本不兼容引起的。本文将提供一些可能的解决方案。 解决方案: 以下是几条可能有用的解决方案: 1.检查Laravel框架版本 在使用Laravel框架时,如果您遇到调度执行错误,那么第一步是检查您使用的Laravel框架版本是否与您的代码兼容…

    other 2023年6月27日
    00
  • C++接口文件小技巧之PIMPL详解

    C++接口文件小技巧之PIMPL详解 PIMPL(Pointer to Implementation) PIMPL模式(指针实现标准库技术)是一种C++的编程技巧,也成为“编译期实现技术”(CTT)。指使用一个指针来指向一个接口类的指针,通过这个指针向实现类的指针,实现对实现类的访问。 PIMPL主要使用技术: 前置声明提高编译速度,减少编译时间 指针类实现…

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