美文网首页
非阻塞套接字与IO多路复用

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

作者: Python野路子 | 来源:发表于2018-09-14 00:33 被阅读0次

普通套接字实现的服务端有什么缺陷呢?

服务端:

import socket

server = socket.socket()  # 创建一个套接字,默认使用IPV4和TCP
server.bind(('0.0.0.0', 7001))  # 绑定ip和端口(注意这里是元组)到套接字,4个0表示任何地址可以访问
server.listen()  # 开启TCP监听

print('等待客户端的到来.....')

while True:
    conn, addr = server.accept()  # 处理客户端的连接,阻塞 等待客户连接
    print('来自{}的连接'.format(addr))
    while True:
        data = conn.recv(1024)  #阻塞
        if data==b'':  ##如果客户端断开了,则会不断的循环,所以需要判断处理
            conn.close()
            break
        else:
            print('接受消息%s'%data.decode())
            conn.send(data)

客户端:

import socket

client = socket.socket()

client.connect(('127.0.0.1', 7001))

while True:
    message = input('发送消息>>>')
    if message !='q':
        client.send(message.encode())
        data = client.recv(1024)
        print('接受的消息>>{}'.format(data.decode()))

    else:
        client.close()
        print('close client socket')
        break
image.png
缺陷:

从上面可以看出普通的套接字一次只能服务一个客户端

缺陷造成原因:
  • accept阻塞:当没有套接字连接请求过来的时候会一直等待着
  • recv阻塞:当连接的这个客户端没有发数据过来的时候,也会一直等待着。

基本IO模型

image.png

非阻塞套接字与非阻塞IO模型

非阻塞套接字和普通套接字的区别?

非阻塞套接字在accept或recv的时候不会发生阻塞,要么成功,要么失败抛出BlockingIOError异常。

非阻塞IO模型

image.png image.png

使用非阻塞套接字实现并发

  • 什么是并发?
    在一个时间段,完成某件事,就是并发
    实现并发思路:将程序中阻塞的地方都避免掉,让cpu一直工作。
import socket


server = socket.socket()
server.setblocking(False)   #将socket设置为非阻塞,必须在创建socket对象后就进行该操作
server.bind(('0.0.0.0', 7001))  #绑定ip和端口(注意这里是元组)到套接字,4个0表示任何地址可以访问
server.listen()

clientList = []
print('等待客户端的到来.......')

while True:
    try:
        conn,addr = server.accept()    #处理客户端的连接,没有连接就引发BlockingIOError异常,返回值是一对 (conn, address),其中conn是一个新的套接字对象
                                       #可以用于在连接上发送和接收数据,地址是绑定到连接另一端的套接字的地址。

        conn.setblocking(False)  #对等连接套接字设置非阻塞
        clientList.append(conn)  #保存已经生成的对等套接字

        print('来自{}的连接'.format(addr))

    except BlockingIOError as e:
        pass

    #处理连接上来的客户端发送数据
    tempList = [conn for conn in clientList]   #利用列表推导式生成了一个临时列表用来去for遍历,而原来的用于移除
    for conn in tempList:
        try:
            data = conn.recv(1024)
            if data:
                print('接受消息:{}'.format(data.decode()))
                conn.send(data)
            else:
                conn.close()
                clientList.remove(conn)  #移除断开的对等套接字
                break
        except BlockingIOError as e:
            pass
image.png
非阻塞套接字实现的服务端还有什么不完美的地方吗?
  • 关键一: 任何操作都是要花CPU资源的!
  • 关键二: 如果数据还没有到达。那么accept, recv操作都是在做无用功!
  • 关键三: 对异常BlockIOError的处理也是在做无用功!
    总结:不完美的CPU利用率

IO多路复用

IO多路复用也是阻塞IO, 只是阻塞的方法是select/poll/epoll, 好处就是单个进程可以处理多个socket。用select,poll,epoll监听多个io对象,当io对象有变化(有数据)的时候,则立即通知相应程序进行读或者写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写时间就绪后自己负责进行读写,也就是说这个读写过程是阻塞的。

IO多路复用模型

image.png
epoll目前Linux上效率最高的IO多路复用 技术 !

epoll

epoll 基于惰性的事件回调机制。
惰性的事件回调是由用户自己调用的,操作系统只起到通知的作用。


image.png

使用步骤

  1. 导入IO多路复用选择器
  2. 注册事件和回调
  3. 查询
  4. 回调
import socket
import selectors

server = socket.socket()
server.bind(('0.0.0.0', 7001))  #绑定ip和端口(注意这里是元组)到套接字,4个0表示任何地址可以访问
server.listen()

epoll = selectors.EpollSelector() #生成epoll,epoll是linux上的


def read(conn):
    data = conn.recv(1024)
    if data==b'':
        epoll.unregister(conn) #数据读完就不用再监控了,取消注册
        conn.close()
    else:
        print('收到的数据>>{}'.format(data.decode()))
        conn.send(data)

def accept(server):
    conn,addr = server.accept()
    ##注册 给他3个参数1.想看什么,看的是server 2.有没有数据连接(EVENT_READ可读,EVENT_WRITE可写)  3.回调函数
    epoll.register(conn, selectors.EVENT_READ,read)  #注册时间及回调


epoll.register(server, selectors.EVENT_READ,accept)


while True:
    events = epoll.select()  #查询所有已经准备好的事件
    for key,mask in events:
        callback = key.data  #函数的名字
        sock = key.fileobj  #套接字
        callback(sock)  #函数调用

相关文章

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

    普通套接字实现的服务端有什么缺陷呢? 服务端: 客户端: 缺陷: 从上面可以看出普通的套接字一次只能服务一个客户端...

  • 阻塞I/O、非阻塞I/O和I/O多路复用

    看概念:阻塞I/O、非阻塞I/O和I/O多路复用 - skiler - 博客园 图解阻塞io和非阻塞io及多路复用...

  • 非阻塞套接字和IO多路复用

    (一)同步阻塞IO模型 1、IO就是输入和输出(即是读和写) 2、接收数据即为input,发送数据即...

  • 细谈Select,Poll,Epoll

    阻塞 io 模型 blocking IO非阻塞 io 模型 nonblocking IOio多路复用模型 IO m...

  • 高级IO

    本篇文章主要涉及的内容有阻塞和非阻塞IO,同步异步IO,还有网络套接字IO,包括select,poll,epoll...

  • IO模型

    描述 本文摘自UNIX网络编程卷1:套接字联网API,描述了UNIX中五种IO模型。阻塞IO、非阻塞IO、IO复用...

  • 使用python编写一个异步非阻塞模块

    异步IO请求的本质则是【非阻塞Socket】+【IO多路复用】

  • 1.Nette入门第一章——IO演进

    1. IO 基础 1.1. linux网络IO模型 阻塞IO模型 非阻塞IO模型 IO多路复用模型(NIO) 信...

  • netty学习主目录

    学习基础 四种io模型(同步阻塞io,同步非阻塞io,io多路复用(select/poll,epoll),异步io...

  • Netty和NIO-未完待续

    linux底层支持bio(阻塞io),nio(多路复用io),aio(异步非阻塞io),信号io等多种方案; jd...

网友评论

      本文标题:非阻塞套接字与IO多路复用

      本文链接:https://www.haomeiwen.com/subject/hixngftx.html