python并发网络通信模型

并发网络通信模型

常见网络模型

  • 循环服务器模型:循环接受客户端请求,处理请求.同一时刻只能处理一个请求,处理完毕后在处理下一个

优点:实现简单,占用资源少

缺点:无法同时处理多个客户端请求

适用情况:处理的任务可以很快完成,客户端无需长期占用服务端程序.UDP比TCP更适合循环

  • 多进程/线程网络并发模型:每当一个客户端连接服务器,就创建一个新的进程/线程为该客户端服务,客户端退出时在销毁该进程/线程

优点:能同时满足多个客户端长期占有服务端需求,可以处理各种请求

缺点:资源消耗较大

适用情况:客户端同时连接量较少,需要处理行为较复杂情况

  • IO并发模型:利用IO多路复用,异步IO等技术,同时处理多个客户端IO请求

优点:资源消耗少,能同时高效处理多个IO行为

缺点:只能处理并发产生的IO事件,无法处理CPU计算

适用情况:HTTP请求,网络传输等都是IO行为

基于fork的多进程网络并发模型

实现步骤

  1. 创建监听套接字
  2. 等待接受客户端请求
  3. 客户端连接创建新的进程处理客户端请求
  4. 原进程继续等待其他客户端连接
  5. 如果客户端退出,则销毁对应的进程

fork代码示例:

 1 from socket import *
 2 import os
 3 import signal
 4 
 5 ADDR = ('127.0.0.1',8080)
 6 
 7 def han(c):
 8     while True:
 9         data = c.recv(1024).decode()
10         if not data:
11             break
12         print(data)
13         c.send(b'OK')
14 #创建套接字监听
15 s = socket()
16 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
17 s.bind(ADDR)
18 s.listen(5)
19 
20 signal.signal(signal.SIGCHLD,signal.SIG_IGN)
21 print("端口连接 8080...")
22 
23 while True:
24     #循环等待客户端连接
25     try:
26         c,addr = s.accept()
27         print("连接中...",addr)
28     except KeyboardInterrupt:
29         os._exit(0)
30     except Exception as e:
31         print(e)
32         continue
33 
34 #创建新进程
35     pid = os.fork()
36     if pid == 0:
37         #子进程处理具体的客户端
38         s.close()
39         han(c)  #具体处理请求
40         os._exit(0) #子进程处理请求后销毁
41 
42     else:
43         pass
View Code

基于threading的多线程网络并发

 实现步骤

  1. 创建监听套接字
  2. 等待接收客户端请求
  3. 客户端连接创建新的线程处理客户端请求
  4. 主线程继续等待其他客户端连接
  5. 如果客户端退出,则对应分支线程退出

threading代码示例:

 1 from socket import *
 2 from threading import Thread
 3 import os
 4 
 5 ADDR = ('0.0.0.0',8888)
 6 
 7 # 客户端处理函数,循环收发消息
 8 def handle(c):
 9     while True:
10         data = c.recv(1024).decode()
11         if not data:
12             break
13         print(data)
14         c.send(b'OK')
15 
16 # 创建监听套接字
17 s = socket()
18 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
19 s.bind(ADDR)
20 s.listen(5)
21 
22 print("Listen the port 8888....")
23 
24 while True:
25     # 循环等待客户端连接
26     try:
27         c,addr = s.accept()
28         print("Connect from",addr)
29     except KeyboardInterrupt:
30         os._exit(0)
31     except Exception as e:
32         print(e)
33         continue
34 
35     # 创建新的线程处理请求
36     client = Thread(target=handle,args=(c,))
37     client.setDaemon(True)
38     client.start()
View Code

 

ftp文件服务器

小练习

功能

  1. 分为服务端和客户端,要求可以有多个客户端同时操作
  2. 客户端可以查看服务器文件库中有什么文件
  3. 客户端可以从文件库中下载文件到本地
  4. 客户端可以上传一个本地文件到文件库
  5. 使用print在客户端打印命令输入提示,引导操作

ftp服务端代码示例:

  1 from socket import *
  2 from threading import Thread
  3 import os,sys
  4 import time
  5 
  6 # 全局变量
  7 HOST = '0.0.0.0'
  8 PORT = 8080
  9 ADDR = (HOST,PORT)
 10 FTP = "/home/tarena/FTP/" # 文件库路径
 11 
 12 # 功能类 (线程类)
 13 # 查文档, 下载,上传
 14 class FTPServer(Thread):
 15     def __init__(self,connfd):
 16         super().__init__()
 17         self.connfd = connfd
 18 
 19     # 处理文件列表
 20     def do_list(self):
 21         # 获取文件列表
 22         files = os.listdir(FTP)
 23         if not files:
 24             self.connfd.send("文件库为空".encode())
 25             return
 26         else:
 27             self.connfd.send(b'OK')
 28             time.sleep(0.1)
 29         # 拼接文件
 30         filelist = ''
 31         for file in files:
 32             filelist += file + '\n'
 33         self.connfd.send(filelist.encode())
 34 
 35     def do_get(self,filename):
 36         try:
 37             f = open(FTP+filename,'rb')
 38         except Exception:
 39             # 文件不存在
 40             self.connfd.send('文件不存在'.encode())
 41             return
 42         else:
 43             self.connfd.send(b'OK')
 44             time.sleep(0.1)
 45 
 46         # 发送文件
 47         while True:
 48             data = f.read(1024)
 49             if not data:
 50                 time.sleep(0.1)
 51                 self.connfd.send(b'##')
 52                 break
 53             self.connfd.send(data)
 54 
 55     def do_put(self,filename):
 56         if os.path.exists(FTP+filename):
 57             self.connfd.send("文件已存在".encode())
 58             return
 59         else:
 60             self.connfd.send(b'OK')
 61         # 接收文件
 62         f = open(FTP + filename,'wb')
 63         while True:
 64             data = self.connfd.recv(1024)
 65             if data == b'##':
 66                 break
 67             f.write(data)
 68         f.close()
 69 
 70     # 循环接受来自客户端的请求
 71     def run(self):
 72         while True:
 73             request=self.connfd.recv(1024).decode()
 74             if not request or request == 'Q':
 75                 return # 线程退出
 76             elif request == 'L':
 77                 self.do_list()
 78             elif request[0] == 'G':
 79                 filename = request.split(' ')[-1]
 80                 self.do_get(filename)
 81             elif request[0] == 'P':
 82                 filename = request.split(' ')[-1]
 83                 self.do_put(filename)
 84 
 85 # 启动函数
 86 def main():
 87     # 创建监听套接字
 88     s = socket()
 89     s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
 90     s.bind(ADDR)
 91     s.listen(5)
 92 
 93     print("Listen the port 8080....")
 94 
 95     while True:
 96         # 循环等待客户端连接
 97         try:
 98             c, addr = s.accept()
 99             print("Connect from", addr)
100         except KeyboardInterrupt:
101             os._exit(0)
102         except Exception as e:
103             print(e)
104             continue
105 
106         # 创建新的线程处理请求
107         client = FTPServer(c)
108         client.setDaemon(True)
109         client.start()
110 
111 main()
View Code

 

ftp客户端代码示例:

  1 import time
  2 from socket import *
  3 import sys
  4 
  5 # 服务器地址
  6 ADDR = ('127.0.0.1',8080)
  7 
  8 # 文件处理类
  9 class FTPClient:
 10     # 所有函数都使用sockfd,所以把它变为属性变量
 11     def __init__(self,sockfd):
 12         self.sockfd = sockfd
 13 
 14     def do_list(self):
 15         self.sockfd.send(b'L') # 发送请求
 16         # 等待回复 (服务端能否满足请求)
 17         data = self.sockfd.recv(128).decode()
 18         if data == 'OK':
 19             # 一次性接收所有文件
 20             data = self.sockfd.recv(4096)
 21             print(data.decode())
 22         else:
 23             print(data)
 24 
 25     def do_quit(self):
 26         self.sockfd.send(b'Q') # 退出请求
 27         self.sockfd.close()
 28         sys.exit("谢谢使用")
 29 
 30     def do_get(self,filename):
 31         # 发送请求
 32         self.sockfd.send(('G '+filename).encode())
 33         # 等待回复
 34         data = self.sockfd.recv(128).decode()
 35         if data == 'OK':
 36             f = open(filename,'wb')
 37             # 循环接收内容,写入文件
 38             while True:
 39                 data = self.sockfd.recv(1024)
 40                 if data == b'##': # 发送完成
 41                     break
 42                 f.write(data)
 43             f.close()
 44         else:
 45             print(data)
 46 
 47     def do_put(self,filename):
 48         try:
 49             f = open(filename,'rb')
 50         except Exception as e:
 51             print("该文件不存在")
 52             return
 53         # 发送请求
 54         filename = filename.split('/')[-1]
 55         self.sockfd.send(('P '+filename).encode())
 56         # 等待反馈
 57         data = self.sockfd.recv(128).decode()
 58         if data == 'OK':
 59             while True:
 60                 data = f.read(1024)
 61                 if not data:
 62                     time.sleep(0.1)
 63                     self.sockfd.send(b'##')
 64                     break
 65                 self.sockfd.send(data)
 66             f.close()
 67         else:
 68             print(data)
 69 
 70 # 启动函数
 71 def main():
 72     sockfd = socket()
 73     try:
 74         sockfd.connect(ADDR)
 75     except Exception as e:
 76         print(e)
 77         return
 78 
 79     ftp = FTPClient(sockfd) # 实例化对象,用于调用功能
 80     # 循环发送请求给服务器
 81     while True:
 82         print("""\n
 83           =========Command============
 84           ****       list        ****
 85           ****    get   file     ****
 86           ****    put   file     ****
 87           ****       quit        ****
 88           ============================
 89         """)
 90         cmd = input("输入命令:")
 91         if cmd.strip() == 'list':
 92             ftp.do_list()
 93         elif cmd.strip() == 'quit':
 94             ftp.do_quit()
 95         elif cmd[:3] == 'get':
 96             filename = cmd.split(' ')[-1]
 97             ftp.do_get(filename)
 98         elif cmd[:3] == 'put':
 99             filename = cmd.split(' ')[-1]
100             ftp.do_put(filename)
101         else:
102             print("请输入正确命令")
View Code

 

转载于:https://www.cnblogs.com/-xiaolong/p/11370828.html

你可能感兴趣的:(python并发网络通信模型)