单进程服务器
from socket import * serSocket = socket(AF_INET,SOCK_STREAM) #重复使用绑定的信息 serSocket.setsockopt(sol_socket,so_reuseaddr,1) #四次挥手,服务器先结束,而且想立即运行服务器,还能绑定 localAddr = ("",7788) serSocket.bind(localAddr) serSocket.listen(5) while True: print("-----主进程,等待新客户端的到来-----") newSocket,destAddr = serSocket.accept() print("-----主进程,接下来负责数据处理") try: while True: recvData = newSocket.recv(1024) if len(recvData)>0: print('recv[%s]:%s'%(str(destAddr),recvData)) else: print('[%s]客户端已经关闭'%str(destAddr)) break finally: newSocket.close() serSocket.close()
多进程服务器:
from socket import * from multiprocessing import * from time import sleep def dealWithClient(newSocket,destAddr): while True: recvData = newSocket.recv(1024) if len(recvData)>0: print('recv[%s]:%s'%(str(destAddr),recvData)) else: print('[%s]客户端已经关闭'%str(destAddr)) break newSocket.close() def main(): serSocket = socket(AF_INET,SOCK_STREAM) #重复使用绑定的信息 serSocket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #四次挥手,服务器先结束,而且想立即运行服务器,还能绑定 localAddr = ("",7788) serSocket.bind(localAddr) serSocket.listen(5) try: while True: print("-----主进程,等待新客户端的到来-----") newSocket,destAddr = serSocket.accept() print("-----主进程,接下来负责数据处理[%s]-----"%str(destAddr)) client = Process(target = dealWithClient,args=(newSocket,destAddr)) client.start()
#因为已经向子进程中copy了一份(引用),并且父进程中这个套接字也没有用处了,所以关闭 newSocket.close() finally: serSocket.close() if __name__ == "__main__": main()
多线程服务器:
from socket import * from multiprocessing import * from time import sleep def dealWithClient(newSocket,destAddr): while True: recvData = newSocket.recv(1024) if len(recvData)>0: print('recv[%s]:%s'%(str(destAddr),recvData)) else: print('[%s]客户端已经关闭'%str(destAddr)) break newSocket.close() def main(): serSocket = socket(AF_INET,SOCK_STREAM) #重复使用绑定的信息 serSocket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #四次挥手,服务器先结束,而且想立即运行服务器,还能绑定 localAddr = ("",7788) serSocket.bind(localAddr) serSocket.listen(5) try: while True: print("-----主进程,等待新客户端的到来-----") newSocket,destAddr = serSocket.accept() print("-----主进程,接下来负责数据处理[%s]-----"%str(destAddr)) client = Thread(target = dealWithClient,args=(newSocket,destAddr)) client.start() #因为线程中共享这个套接字,如果关闭了会导致这个套接字不可用, #但是此时在线程中这个套接字可能还在接收数据,因此不能关闭 #newSocket.close() finally: serSocket.close() if __name__ == "__main__": main()
单进程服务器-非阻塞模式
from socket import * from multiprocessing import * from time import sleep serSocket = socket(AF_INET,SOCK_STREAM) #重复使用绑定的信息 localAddr = ("",7788) serSocket.bind(localAddr) #让这个socket变为非阻塞 serSocket.setblocking(False) serSocket.listen(100) clientAddrList = [] #用来保存所有已经连接的客户端的信息 while True: try: clientSocket,clientAddr = serSocket.accept() except: pass else: print("一个新的客户端到来:%s"%str(clientAddr)) clientAddrList.append((newSocket,clientAddr)) for clientSocket,clientAddr in clientAddrList: try: recvData = clientSocket.recv(1024) except: pass else: if len(recvData)>0: print("%s:%s"%(str(clientAddr),recvData)) else: clientSocket.close() clientAddrList.remove((clientSocket,clientAddr)) print("%s已经下线"%str(clientAddr))
select版服务器
import select import socket import sys server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind(("",7788)) server.listen(5) inputs = [server,sys.stdin] running = True while True: # 调用 select 函数,阻塞等待 readable,writeable,exceptional = select.select(inputs,[],[]) # 数据抵达,循环 for sock in readable: # 监听到有新的连接 if sock == server: conn,addr = server.accept() # select 监听的socket inputs.append(conn) # 监听到键盘有输入 elif sock == sys.stdin: cmd = sys.stdin.readline() running = False # 有数据到达 else: # 读取客户端连接发送的数据 data = sock.recv(1024) if data: sock.send(data) else: # 移除select监听的socket inputs.remove(sock) sock.close() # 如果检测到用户输入敲击键盘,那么就退出 if not running: break server.close()
epoll版服务器
import socket import select s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) s.bind(("",7788)) s.listen(10) epoll = select.epoll() # 文件描述符 fileno epoll.register(s.fileno(),select.EPOLLIN|select.EPOLLET) connections = {} addresses = {} while True: #epoll进行fd扫描的地方---未指定超时时间则为阻塞等待 epoll_list = epoll.poll() #对事件进行判断 for fd,events in epoll_list: #如果是socket创建的套接字被激活 if fd == s.fileno(): conn,addr = s.accept() print('有新的客户端到来%s'%str(addr)) #将conn和addr信息分别保存起来 connections[conn.fileno()] = conn addresses[conn.fileno()] =addr #向epoll中注册连接socket的可读事件 epoll.register(conn.fileno(),select.EPOLLIN|select.EPOLLET) elif events == select.EPOLLIN: #判断事件是否是接收数据的事件 #从激活fd上接收 recvData = connections[fd].revc(1024) if len(recvData)>0: print('recv:%s'%recvData) else: epoll.unregister(fd) connections[fd].close() print("%s---offline---"%str(addresses[fd]))
协程
import time def A(): while True: print("----A----") yield time.sleep(0.5) def B(c): while True: print("----B----") next(c) time.sleep(0.5) if __name__ == "__main__": a = A() B(a)
greenlet实现多任务
sudo pip3 install greenlet
协程由开发者决定什么时候切,而进程、线程由操作系统决定什么时候切
from greenlet import greenlet import time def test1(): while True: print("-----A-----") gr2.switch() time.sleep(0.5) def test2(): while True: print("-----B-----") gr1.switch() time.sleep(0.5) gr1 = greenlet(test1) gr2 = greenlet(test2) gr1.switch()
gevent版服务器
sudo pip3 install gevent
import gevent def f(n): for i in range(n): print(gevent.getcurrent(),i) gevent.sleep(1) g1 = gevent.spawn(f,5) g2 = gevent.spawn(f,5) g3 = gevent.spawn(f,5) g1.join() g2.join() g3.join()
gevent版-tcp服务器
import sys import time import gevent from gevent import socket,monkey monkey.patch_all() #打补丁,把python代码改掉,耗时操作切换 def handle_request(conn): while True: data = conn.recv(1024) if not data: conn.close() break print("recv",data) conn.send(data) def server(port): s = socket.socket() s.bind(("",port)) s.listen(5) while True: cli,addr = s.accept() gevent.spawn(handle_request,cli) if __name__ == '__main__': server(7788)