首页 > 其他分享 >非阻塞套接字与IO多路复用

非阻塞套接字与IO多路复用

时间:2024-08-20 12:38:40浏览次数:9  
标签:socket 多路复用 epoll tcp client fd IO 接字

非阻塞套接字与IO多路复用

非阻塞套接字

# 【本机环境运行】
# 01-TCP非堵塞通信.py
# 使用 TCP调试助手作为客户端

import socket

tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.bind(("", 9000))
tcp_socket.listen(128)

# 设置监听套接字为非堵塞模式
tcp_socket.setblocking(False)
client_socket_list = []
while True:
    try:
        client_socket, client_addr = tcp_socket.accept()
    except Exception:
        # print("没有客户端接入")
        pass
    else:
        print(f"新的客户端{client_addr}到来")
        # 设置服务套接字为非堵塞模式
        client_socket.setblocking(False)
        # 添加客户端到服务列表
        client_socket_list.append((client_socket, client_addr))

    # 遍历服务套接字<轮询>接收数据
    for client, addr in client_socket_list:
        try:
            recv_data = client.recv(1024)
        except Exception as ret:
            # print("非堵塞未收到数据异常")
            pass
        else:
            # 客户端调用close
            if recv_data:
                print(f"{addr}: {recv_data.decode()}")
            else:
                print(f"客户端{addr}关闭")
                client.close()
                client_socket_list.remove((client, addr))

IO多路复用epoll

epoll工作过程图解

epoll工作流程

# 【虚拟机环境运行】
# 02-epoll实现并发服务器.py

"""
这里的epoll只能运行在linux ,在其他系统上有改版的工具包
"""

from socket import *
import select


class FLServer:

    def __init__(self, bind_ip, port):
        self.tcp_socket = socket(AF_INET, SOCK_STREAM)
        # 重复利用端口
        self.tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 主机作为客户端访问虚拟机,网卡只能使用仅主机模式
        self.tcp_socket.bind((bind_ip, port))
        self.tcp_socket.listen(128)

    def run_server(self):
        # 创建一个epoll对象 (创建一个操作系统和应用程序的共享内存)
        epl = select.epoll()
        # 将监听套接字对应的fd注册到epoll中(添加到共享内存)
        epl.register(self.tcp_socket.fileno(), select.EPOLLIN)

        # 定义服务套接字对应文件描述符和套接字的映射关系{fd: socket}
        fd_socket_map = {}
        while True:
            # os监测数据到来, 通过事件通知方式通知程序(解堵塞); 这里默认堵塞
            events_list = epl.poll()

            # events_list 数据格式 [(fd, event), (套接字的文件对应描述符, 对应事件)...]
            for fd, event in events_list:
                # 监听套接字有输入(有新客户端连接)
                if fd == self.tcp_socket.fileno():
                    tcp_server_socket, client_addr = self.tcp_socket.accept()
                    print(f"【新的客户{client_addr}到来】")

                    # 获取服务套接字的文件描述符并注册到epoll
                    server_socket_fp = tcp_server_socket.fileno()
                    epl.register(server_socket_fp, select.EPOLLIN)

                    # 添加服务套接字与描述符的映射关系到字典
                    fd_socket_map[server_socket_fp] = tcp_server_socket
                    # print(fd_socket_map)

                # 服务器套接字接收到数据
                elif event == select.EPOLLIN:
                    # print(fd_socket_map)
                    client_socket = fd_socket_map[fd]
                    recv_data = client_socket.recv(1024)
                    if recv_data:
                        print(f"接收到数据: {recv_data.decode('gbk')}")
                    else:
                        # 关闭套接字
                        client_socket.close()
                        # 注销套接字对应的fd
                        epl.unregister(fd)
                        # 删除对应客户端的 事件描述与符套接字映射关系
                        fd_socket_map.pop(fd)

        self.tcp_socket.close


def main():
    ip = "192.168.56.101"
    port = 8888

    print(f"http服务器已启动:\n服务器IP地址: {ip}\n服务器端口号: {port}")
    http_server = FLServer(ip, port)
    http_server.run_server()


if __name__ == '__main__':
    main()


  • 这里的epoll只能运行在linux,在其他系统上有改版的工具包
  • epoll能够高效运行的原因

    1. 事件监听工作方式
    2. 与操作系统共享内存,减少文件拷贝耗时
  • I/O 多路复用的特点:

    • 通过一种机制使一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,epoll()函数就可以返回。 所以, IO多路复用,本质上不会有并发的功能,因为任何时候还是只有一个进程或线程进行工作,它之所以能提高效率是因为select\epoll 把进来的socket放到他们的 '监视' 列表里面,当任何socket有可读可写数据立马处理,那如果select\epoll 手里同时检测着很多socket, 一有动静马上返回给进程处理,总比一个一个socket过来,阻塞等待,处理高效率。
    • 当然也可以多线程/多进程方式,一个连接过来开一个进程/线程处理,这样消耗的内存和进程切换页会耗掉更多的系统资源。 所以我们可以结合IO多路复用和多进程/多线程 来高性能并发,IO复用负责提高接受socket的通知效率,收到请求后,交给进程池/线程池来处理逻辑。
  • epollLinux中的实现过程可参考 [epoll详解直达](

标签:socket,多路复用,epoll,tcp,client,fd,IO,接字
From: https://www.cnblogs.com/cs-songbai/p/18369258

相关文章

  • 神经网络之卷积篇:详解单层卷积网络(One layer of a convolutional network)
    详解单层卷积网络如何构建卷积神经网络的卷积层,下面来看个例子。已经写了如何通过两个过滤器卷积处理一个三维图像,并输出两个不同的4×4矩阵。假设使用第一个过滤器进行卷积,得到第一个4×4矩阵。使用第二个过滤器进行卷积得到另外一个4×4矩阵。最终各自形成一个卷积神经网络......
  • EOFException com.mysql.cj.protocol.FullReadInputStream in readFully
    背景:mysql查询性能瓶颈,一般前提有很多查询超时导致这个问题java.io.EOFException:Cannotreadresponsefromserver.Expectedtoread4bytes,read0bytesbeforeconnectionwasunexpectedlylost.atcom.mysql.cj.protocol.FullReadInputStream.readFully(FullRe......
  • C#的Action和Func委托
    Action委托:1.声明和使用不带参数的 Action 委托:ActionmyAction=()=>Console.WriteLine("HelloWorld!");myAction();2.声明和使用带有一个参数的 Action 委托:Action<string>myAction=(message)=>Console.WriteLine(message);myAction("HelloWorld!"......
  • 【pipenv】failed to create virtual enviroment: TypeError: canonicalize_version()
    环境:python--versionPython3.9.1pip--versionpip24.2pipshowpipenv2024.0.1pipshowsetuptools73.0.0未成功的解决方案:升级各个版本:pipinstall--upgradepipsetuptoolspipinstall--upgradepipenvpipenv--clearpipenvinstall--skip-lockpipinsta......
  • 学习文件IO,让你从操作系统内核的角度去理解输入和输出(理论篇)
    本篇会加入个人的所谓鱼式疯言❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......
  • VTK—vtkImplicitFunction 隐函数
    通过这个例子可以直观理解隐函数是什么、在空间中怎么分布、怎么布尔运算。1.完整代码#include<vtkBox.h>#include<vtkNew.h>#include<vtkActor.h>#include<vtkSphere.h>#include<vtkAutoInit.h>#include<vtkProperty.h>#include<vtkRenderer.h>#include<vtkIm......
  • [Base]WTComv-Wavelet Convolutions for Large Receptive Fields
    1.BaseInfoTitleWaveletConvolutionsforLargeReceptiveFieldsAdresshttps://arxiv.org/pdf/2407.05848Journal/TimeECCV2024Author以色列本古里安Codehttps://github.com/BGU-CS-VIL/WTConv2.CreativeQ&A卷积核7x7时性能饱和。卷积层CNN响应高频较多,Attent......
  • 解决nvm ls-remote 列表只出现iojs版本
    前言在nvm安装node时发现显示不存在此版本,使用nvmls-remote查看可安装列表时发现,列表中只有iojs$nvmls-remoteiojs-v1.0.0iojs-v1.0.1iojs-v1.0.2iojs-v1.0.3iojs-v1.0.4iojs-v1.1.0iojs-v1.2.0iojs-v1.3.0iojs-v1.4.1......
  • COS110 - Program Design: Introduction
    DepartmentofComputerScienceFacultyofEngineering,BuiltEnvironment&ITUniversityofPretoriaCOS110-ProgramDesign:IntroductionPractical4SpecificationsReleaseDate:19-08-2024at06:00DueDate:23-08-2024at23:59TotalMarks:1501Con......
  • 基于STM32F407ZGT6芯片的GPIO工作模式
    目录4种输入模式4种输出模式输入模式模拟输入浮空输入上拉输入下拉输入输出模式推挽输出开漏输出复用推挽输出复用开漏输出4种输入模式(1)GPIO_Mode_IN_FLOATING浮空输入(2)GPIO_Mode_IPU上拉输入(3)GPIO_Mode_IPD下拉输入(4)GPIO_Mode_AIN模拟输入4种输出模......