python第10天(下)

Posted Mr-Lf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python第10天(下)相关的知识,希望对你有一定的参考价值。

https://www.cnblogs.com/zingp/p/6863170.html 

 

一:IO模型介绍

IO发生时涉及的对象和步骤

  对于一个网络IO(network IO),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)

  当一个read操作发生时,该操作会经历两个阶段:

   1)等待数据准备 (Waiting for the data to be ready)

  2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process) 

  记住这两点很重要,因为这些IO模型的区别就是在两个阶段上各有不同的情况

 

 1  1 import socket
 2  2 server=socket.socket()
 3  3 server.bind(("localhost",6969))
 4  4 server.listen()
 5  5 print("等待用户链接")
 6  6 while True:
 7  7     conn,addr=server.accept()
 8  8     while True:
 9  9         conn.send(("%s have connected to server"%addr).encode())
10 10         data=conn.recv(1024)
11 11         print("from client",data.decode())
12 12 
13 13 
14 14 import socket
15 15 client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
16 16 client.connect(("localhost",6969))
17 17 while True:
18 18     data=client.recv(1024)
19 19     print("from server:",data.decode())
20 20     client.send("hellow".encode())
阻塞IO

 1 import socket,time
 2 server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 3 server.bind(("localhost",6969))
 4 server.listen()
 5 server.setblocking(False)#设置为非阻塞,默认为阻塞
 6 print("等待用户链接")
 7 while True:
 8     try:
 9         conn,addr=server.accept()
10         conn.send("you have connected to server".encode())
11         data=conn.recv(1024)
12         print("from client",data.decode())
13         conn.close()
14     except Exception as e:
15         print(e)
16         time.sleep(4)
17 ##########
18 import socket,time
19 client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
20 while True:
21     client.connect(("localhost", 6969))
22     data=client.recv(1024)
23     print("from server:",data.decode())
24     client.send("hellow".encode())
25     time.sleep(2)
26     break
非阻塞IO

由于设置了非阻塞IO(setblocking())所以在accept()的时候会报错,因为抓住了错误,所以开始会输出错误信息 ,有个问题就是服务端接收不到了客户端的数据

IO multiplexing:包括select,epoll,有些地方也称这种IO方式为event driven IO

注意1:select函数返回结果中如果有文件可读了,那么进程就可以通过调用accept()或recv()来让kernel将位于内核中准备到的数据copy到用户区

一:流程

 

二:IO多路复用的触发方式

  • 水平触发
  • 边缘触发

三:select实例

 1 import socket
 2 import select
 3 server=socket.socket()
 4 server.bind(("localhost",6969))
 5 server.listen()
 6 while True:
 7     r,w,e=select.select([server,],[],[],5)
 8     #rlist -- wait until ready for reading
 9     #wlist -- wait until ready for writing
10     #xlist -- wait for an ``exceptional condition\'\'
11     #阻塞等待链接的时间
12     for i in r:
13         print(r)
14         conn,addr=i.accept()
15         print(conn)
16         print(addr)
17         print("hellow")
18     print(">>>>>")
19 ####################
20 
21 import socket,time
22 client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
23 while True:
24     client.connect(("localhost", 6969))
25     print(client)
26     data=client.recv(1024)
27     print("from server:",data.decode())
28     client.send("hellow".encode())
select实现IO多路复用

在不调用accept的时候,会反复的输出hellow和>是因为select的触发方式为水平触发

 1 import select,socket
 2 server=socket.socket()
 3 server.bind(("localhost",6969))
 4 server.listen(5)
 5 inp=[server,]
 6 while True:
 7     r, w, e = select.select(inp, [], [])
 8     for obj in r:
 9         if obj == server:
10             print("r:", r)
11             print(len(r))
12             print(obj)
13             conn, addr = obj.accept()
14             inp.append(conn)
15         else:
16             print("obj:",obj)
17             data=obj.recv(1024).decode()
18             print(">>:",data)
19             data=input("回答%s:"%str(addr))
20             obj.send(data.encode())
21 ###################################
22 import socket
23 client=socket.socket()
24 client.connect(("localhost",6969))
25 print(client)
26 while True:
27     inp=input(">>>>:")
28     client.send(inp.encode())
29     data=client.recv(1024).decode()
30     print(data)
select实现监听多链接

 

异步IO全程无阻塞

 

 1 import selectors
 2 import socket
 3 def accept(server,mask):
 4     conn,addr=server.accept()
 5     print("client_sock:%s\\nclient_addr:%s"%(conn,addr))
 6     sel.register(conn,selectors.EVENT_READ,read)#注册,将conn和read函数绑定
 7 def read(conn,mask):
 8     try:#window如果客户端断开链接会报错,但是如果是linux客户端断开会发空数据,检测断开手段不一样
 9         data=conn.recv(1024)
10         print(data.decode())
11         conn.send(data)
12     except Exception as e:
13         print("close:%s"%conn)
14         sel.unregister(conn)#解除绑定
15         conn.close()
16 if __name__ == \'__main__\':
17 
18     sel=selectors.DefaultSelector()#生成一个selector的对象
19     print("sel:",sel)
20     server=socket.socket()
21     server.bind(("localhost",6969))
22     server.listen()
23     sel.register(server,selectors.EVENT_READ,accept)#注册,将server与accept绑定
24     while True:
25         events=sel.select()#相当于select.select()#检测是否有链接或已连接的socket是否发送数据
26         print("events:",events)
27         print("\\n")
28         for key,mask in events:
29             print("key:",type(key),key)#(SelectorKey(fileobj=<socket.socket fd=536, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=(\'127.0.0.1\', 6969)>, fd=536, events=1, data=<function accept at 0x02C14E40>)
30             callback=key.data
31             callback(key.fileobj,mask)#调用相应的函数
selctor实现IO多路复用

 


 

以上是关于python第10天(下)的主要内容,如果未能解决你的问题,请参考以下文章

python课程第10天《函数》

第10天:Python 类与对象

python全栈开发第10天-正则表达式

第43天python学习re模块学习

Python学习第101天(mysql索引)

Python学习第101天(mysql索引)