优势:实现简单,占用资源少服务器
缺点:没法同时处理多个客户端请求网络
适用状况:处理的任务能够很快完成,客户端无需长期占用服务端程序.UDP比TCP更适合循环多线程
优势:能同时知足多个客户端长期占有服务端需求,能够处理各类请求并发
缺点:资源消耗较大异步
适用状况:客户端同时链接量较少,须要处理行为较复杂状况socket
优势:资源消耗少,能同时高效处理多个IO行为ide
缺点:只能处理并发产生的IO事件,没法处理CPU计算函数
适用状况:HTTP请求,网络传输等都是IO行为ui
实现步骤spa
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
实现步骤
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()
ftp文件服务器
小练习
功能
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()
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("请输入正确命令")