python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)

时间:2021-07-25 00:00:54

9.16 非阻塞IO模型

cpu占用率过高

服务端:

from socket import *
import time
s = socket()
s.bind(('127.0.0.1',8080))
s.listen(5)
s.setblocking(False)    #使accept接收不到连接时不在阻塞
​
r_list=[]
while True:
    try:
        conn, addr = s.accept()
        r_list.append(conn)
    except BlockingIOError:
        # time.sleep(3)
        #print('可以去干其他的活了')
        #print('rlist: ',len(r_list))
        for conn in r_list:
            try:
                data=conn.recv(1024)
                conn.send(data.upper())
            except BlockingIOError:
                continue

客户端;

from socket import *
import os
client = socket()
client.connect(('127.0.0.1', 8080))
​
while True:
    data='%s say hello' %os.getpid()
    client.send(data.encode('utf-8'))
    res=client.recv(1024)
    print(res.decode('utf-8'))

9.17 I/O多路复用

服务端:

python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)
from socket import *
import select
s = socket()
s.bind(('127.0.0.1',8080))
s.listen(5)
s.setblocking(False)                        #使accept接收不到连接时不在阻塞
# print(s)
​
r_list=[s,]
w_list=[]
w_data={}
while True:
    print('被检测r_list: ',len(r_list))
    print('被检测w_list: ',len(w_list))      #rl中是r_list中建立连接的套接字对象
    rl,wl,xl=select.select(r_list,w_list,[],) #r_list=[server,conn]
    # print('rl: ',len(rl)) #rl=[conn,]
    # print('wl: ',len(wl))
# 收消息
    for r in rl: #r=conn
        if r == s:
            conn,addr=r.accept()
            r_list.append(conn)
        else:
            try:
                data=r.recv(1024)
                if not data:
                    r.close()
                    r_list.remove(r)
                    continue
                # r.send(data.upper())
                w_list.append(r)
                w_data[r]=data.upper()
            except ConnectionResetError:
                r.close()
                r_list.remove(r)
                continue
    # 发消息
    for w in wl:
        w.send(w_data[w])
        w_list.remove(w)
        w_data.pop(w)
View Code

客户端:

python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)
from socket import *
import os
client = socket()
client.connect(('127.0.0.1', 8080))
​
while True:
    data='%s say hello' %os.getpid()
    client.send(data.encode('utf-8'))
    res=client.recv(1024)
    print(res.decode('utf-8'))
View Code

9.18 socketserver的使用

9.181 基于tcp的socketserver

服务端:

import socketserver
# 通信循环
class MytcpHandler(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                data = self.request.recv(1024)  # 1024 接收数据的最大限制
                if not data: break  # 针对linux系统
                self.request.send(data.upper())  # 注意:收发都是以bytes为单位
            except ConnectionResetError:
                break
        self.request.close()
​
if __name__ == '__main__':
    #连接循环
    server=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MytcpHandler)
    server.serve_forever()
​
    print(server.server_address)
    print(server.RequestHandlerClass)
    print(server.socket)

客户端:

import socket
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
​
while True:
    msg=input('>>: ').strip()
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))
client.close()

9.182 基于udp的socketserver

服务端:

python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)
import socketserver
# 通信循环
class MyUDPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request)#(b'13404 hello', <socket.socket fd=460, family=AddressFamily.AF_INET, 
        res=self.request[0]#type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
        print('客户端发来的数据:',res)
        
        self.request[1].sendto(res.upper(),self.client_address)
​
if __name__ == '__main__':
    #连接循环
    server=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPHandler)
    server.serve_forever()
View Code

客户端:

python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)python 之 并发编程(非阻塞IO模型、I/O多路复用、socketserver的使用)
import socket
import os
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
​
while True:
    msg='%s hello' %os.getpid()
    client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
​
    res,server_addr=client.recvfrom(1024)
    print(res)
View Code