Python

it2025-05-01  8

0、承上

   进程:

    计算机里最小的资源分配单位;

    数据隔离, 利用多核,数据不安全。

 

  线程:

    计算机中最小的CPU调度单位;

    数据共享,GIL锁,数据不安全.

 

  协程:

    线程的一部分,是有用户来调度的;

    数据共享,数据安全.

 

  异步:  同时做不止一件事情.

 

  同步:  事情一件接着一件 的做.

 

  阻塞:  recv、recvfrom、accept、sleep、input

 

  非阻塞:平时遇见的处过上边基本上都是。

 

  IO操作:

    网络相关的操作

    文件处理、json.dump/load、logging、print、input、recv/send、connect/accept、recvfrom/sendto

 

  recv为什么要阻塞?

    等待数据到来到Python程序的内存中。

 

 

  IO模型一共有五种,由于信号驱动IO不常用,我们这里主要介绍阻塞IO、非阻塞IO、IO多路复用以及异步IO。

  对于一个network IO(这里以read举例),它会涉及到两个系统对象,一个是调用这个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、阻塞IO( Blocking IO )

   在Linux中,默认情况下所有的socket都是blocking读操作流程大概如下:

 

1 import socket 2 3 sk = socket.socket() 4 sk.setblocking(True) 5 6 # True 阻塞 7 # False 非阻塞 8 # TCP协议的socket sever不能同时接收多个请求 9 # sk.accept() 10 # while True: 11 # conn.recv()

 

  

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

  非阻塞的形式实现了并发的socket server.

  非阻塞的形式实现了并发的socket sever,太耗CPU.

  没有数据来的时候程序的高速处理极大地占用了CPU资源.

 

 

 

 

1 import socket 2 3 sk = socket.socket() 4 sk.bind(('127.0.0.1', 9000)) 5 sk.setblocking(False) 6 sk.listen() 7 conn_lst = [] 8 del_lst = [] 9 while True: 10 try: 11 conn,addr = sk.accept() # 非阻塞,没有连接来就报错 12 conn_lst.append(conn) 13 print(conn) 14 except BlockingIOError: 15 for con in conn_lst: 16 try: 17 con.send(b'hello') 18 try: 19 print(con.recv(1024)) # 非阻塞 没有消息来就报错 20 except BlockingIOError: # 没有消息就报错 21 pass 22 except ConnectionResetError: # send没有连接的报错 23 con.close() 24 del_lst.append(con) 25 for con in del_lst: 26 conn_lst.remove(con) 27 del_lst.clear() 服务器端 1 import socket 2 3 sk = socket.socket() 4 sk.connect(('127.0.0.1', 9000)) 5 while True: 6 print(sk.recv(1024)) 7 sk.send(b'bye') 8 sk.close() 客户端

 

  sever:

 

 

 结果:

D:\Python36\python.exe E:/Python/草稿纸0.py <socket.socket fd=268, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 51839)> b'bye' b'byebye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'bye' b'byebye' b'bye' b'bye' b'bye' b'byebye' b'bye' b'bye' b'bye' b'bye' Process finished with exit code 1 服务器端 D:\Python36\python.exe E:/Python/草稿纸.py b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hello' b'hellohellohello' b'hello' b'hello' b'hellohellohello' b'hello' b'hello' b'hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello' b'hellohello' b'hello' 客户端结果

 

   由于通信的一直是小数据块(大小不够1024),出现了黏包现象. 

 

3、IO多路复用(IO multiplexing)

 

 

 

 

1 import select 2 import socket 3 4 sk = socket.socket() 5 sk.bind(('127.0.0.1', 9000)) 6 sk.setblocking(False) 7 sk.listen() 8 9 rlst = [sk] # 监听的是对象的读操作 10 wlst = [] # 监听的是对象的写操作 11 xlst = [] # 监听的是对象的异常操作 12 while True: 13 rl,wl,xl = select.select(rlst, wlst, xlst) 14 for obj in rl: 15 if obj == sk: 16 conn,addr = sk.accept() 17 rlst.append(conn) 18 else: 19 msg = obj.recv(1024) 20 if msg == b'': 21 obj.close() 22 rlst.remove(obj) 23 continue 24 print(msg) 25 obj.send(b'hello') IO多路复用-sever端 1 import socket 2 3 sk = socket.socket() 4 sk.connect(('127.0.0.1', 9000)) 5 while True: 6 sk.send(b'wahaha') 7 print(sk.recv(1024)) 8 sk.close() IO多路复用-client端

 

 

  socketsever —— TCP协议的并发操作  selectors + 多线程

  IO多路复用的select的工作机制

    select  Windows  轮询

    poll      Linux        轮询,poll能够监听的对象比select要多

    epoll    Linux        不是采用轮询的方式,而是采用回调函数的形式

 

 

转载于:https://www.cnblogs.com/ZN-225/p/9203674.html

最新回复(0)