python IO模型和多路复用客户端服务端

IO 涉及到的对象和步骤

#
# # 前提需知道:操作系统的内核态和用户态 ,通信将数据缓存到内核,然后操作系统执行accept到用户态
#
# # IO发生时涉及的对象:
# # 对于一个network IO (这里我们以read举例),它会涉及到两个系统对象:
# # 一个是调用这个IO的进程或者线程
# # 另一个就是系统内核(kernel)
# #
# #
# # IO发生时涉及的步骤:
# # 当一个read操作发生时,它会经历两个阶段:
# #  1 等待数据准备 (Waiting for the data to be ready)
# #  2 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)
# # 记住这两点很重要,因为这些IO Model的区别就是在两个阶段上各有不同的情况。
# # 在linux中,默认情况下所有的socket都是blocking,即阻塞IO。
#

  

1、blocking IO (阻塞IO):

#
#     当用户进程调用了recvfrom这个系统调用,内核kernel就开始了IO的第一个阶段:准备数据。
#     对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),
#     这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。
#
#     当内核kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,
#     用户进程才解除block的状态,重新运行起来。
#     所以,blocking IO的特点就是在IO执行的两个阶段都被block了。
#
#     简单总结:数据没来,一直等,没数据,复制也不行,一直等
#

  

2、non-blocking IO(非阻塞IO)

# linux下,可以通过设置socket使其变为non-blocking。
#
#     当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。
#     用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。
#     所以,用户进程其实是需要不断的主动询问kernel数据好了没有。进程在返回之后,可以干点别的事情,然后继续轮询。
#     注意,复制数据阶段仍然处于阻塞阶段。
#
#

  

3、IO multiplexing(IO多路复用)

#     IO multiplexing这个词可能有点陌生,但是如果我说select,epoll,大概就都能明白了。
#     有些地方也称这种IO方式为event driven IO。我们都知道,
#     select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。
#     它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,
#     当某个socket有数据到达了,就通知用户进程
#
#     当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,
#     当任何一个socket中的数据准备好了,select就会返回。
#     这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
#
# 用select的优势在于它可以同时处理多个connection。
# 所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定
# 比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。
# select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。
#
#
# 注意1:select函数返回结果中如果有文件可读了,那么进程就可以通过调用accept()或recv()
# 来让kernel将位于内核中准备到的数据copy到用户区。
#
# 注意2: select的优势在于可以处理多个连接,不适用于单个连接

  

4、AsynchronousI / O(异步IO):

#     用户进程发起read操作之后,立刻就可以开始去做其它的事。
#     而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,
#     所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,
#     当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
#
#

 

5、综合

# # 阻塞IO:等数据,数据不来,不走,全程阻塞
# # 一次accept,全程阻塞
#
#
# # 非阻塞io:问你有没有数据,有带着数据走,没有,带着错误走
# # socket.socket().setblocking(False)
# # 缺点:发多次系统调用,拿到的数据不一定是实时的
# # 优点:等待数据时无阻塞
# # 两个阶段:
# # 等待数据非阻塞
# # 复制数据阻塞
#
#
#
# # IO多路复用:(重点)
# # conn没有新链接监听
# # select监听有变化的套接字,有新链接
# # select监听数据,数据到了告诉他,不到就阻塞
#
# # 套接字对象(文件描述符):
# # 是一个非零整数,不会变
# # 收发数据的时候,对于接收端而言,数据先到内核空间,然后 copy
# # 到用户空间,同时,内核空间数据清除。
#
# # 2次调用,全程阻塞,select一次,accept一次
# # 特点:
# # 1全程阻塞(wait for data,copy)
# # 2能监听多个文件描述符
# # 3实现并发
#
# # 异步IO:
# # linux 下用的很少,实现复杂,用的少
#
# # 有一个阻塞就是同步,
# # 同步:阻塞io,非阻塞io,io多路复用
# # 异步:异步io

  

IO多路复用的客户端和服务器端

# IO多路复用client 端

import socket

sock=socket.socket()
sock.connect(("127.0.0.1",8888))

while 1:
    msg=input(">>:")
    sock.send(msg.encode("utf8"))
    data=sock.recv(1024)
    print(data.decode("utf8"))

sock.close()
# IO多路复用server 端

import socket

import select
sock=socket.socket()
sock.bind(("127.0.0.1",8888))

sock.listen(5)

sock.setblocking(False)
inputs=[sock,]

while 1:

    r,w,e=select.select(inputs,[],[])

    for obj in r:
        if obj == sock:
            conn,addr=obj.accept()
            print("conn",conn)
            inputs.append(conn)
        else:
            data = obj.recv(1024)
            print(data.decode("utf8"))

            msg=input(">>>:")
            obj.send(msg.encode("utf8"))

 

转载于:https://www.cnblogs.com/adamans/articles/7568813.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值