1、socketserver
socketserver模块是基于socket而来的模块,内部使用IO多路复用以及多线程和多进程,从而实现并发处理客服端请求的Socket服务器。
即:每个客户端连接到服务器Socket服务端都会在服务端创建一个线程或者进程专门负责处理当前客户端的所有请求。
import socketserver class MyServer(socketserver.BaseRequestHandler): def handle(self): # print self.request,self.client_address,self.server conn = self.request conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.'.encode()) Flag = True while Flag: data = conn.recv(1024) if data.decode() == 'exit': Flag = False elif data.decode() == '0': conn.sendall('通过可能会被录音.balabala一大推'.encode()) else: conn.sendall('请重新输入.'.encode()) if __name__ == '__main__': server = socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyServer) server.serve_forever()
import socket ip_port = ('127.0.0.1',8009) sk = socket.socket() sk.connect(ip_port) sk.settimeout(5) while True: data = sk.recv(1024) print('receive:', data.decode()) inp = input('please input:') sk.sendall(inp.encode()) if inp == 'exit': break sk.close()
运行流程图
从上图我们可以看出SocketServer主要被抽象为两个主要的类: BaseServer类,用于处理连接相关的网络操作 BaseRequestHandler类,用于实际处理数据相关的操作,SocketServer还提供了MixIn类:ThreadingMinxIn使用多进程多线程处理请求。
内部调用流程为:
- 启动服务端程序
- 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
- 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass
- 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
- 当客户端连接到达服务器
- 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
- 执行 ThreadingMixIn.process_request_thread 方法
- 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)
2、使用多进程加select模拟socketServer的运行模式
import socket import threading import select def process(request, client_address): print request,client_address conn = request conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.') flag = True while flag: data = conn.recv(1024) if data == 'exit': flag = False elif data == '0': conn.sendall('通过可能会被录音.balabala一大推') else: conn.sendall('请重新输入.') sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sk.bind(('127.0.0.1',8002)) sk.listen(5) while True: r, w, e = select.select([sk,],[],[],1) print 'looping' if sk in r: print 'get request' request, client_address = sk.accept() t = threading.Thread(target=process, args=(request, client_address)) t.daemon = False t.start() sk.close()
import socket ip_port = ('127.0.0.1',8009) sk = socket.socket() sk.connect(ip_port) sk.settimeout(5) while True: data = sk.recv(1024) print('receive:', data.decode()) inp = input('please input:') sk.sendall(inp.encode()) if inp == 'exit': break sk.close()
3、使用协程并发
使用个gevent 实现server端的并发监控client的连接。
from gevent import monkey; monkey.patch_all() from socket import * import gevent # 如果不想用money.patch_all()打补丁,可以用gevent自带的socket # from gevent import socket # s=socket.socket() def server(server_ip, port): s = socket(AF_INET, SOCK_STREAM) s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) s.bind((server_ip, port)) s.listen(5) while True: conn, addr = s.accept() gevent.spawn(talk, conn, addr) def talk(conn, addr): try: while True: res = conn.recv(1024) print('client %s:%s msg: %s' % (addr[0], addr[1], res)) conn.send(res.upper()) except Exception as e: print(e) finally: conn.close() if __name__ == '__main__': server('127.0.0.1', 8000)
from multiprocessing import Process import socket import time def client(ip,port,i): s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) ip_port = (ip,port) s.connect(ip_port) while True: data = i s.sendall(data.encode('utf-8')) time.sleep(3) data_recv = s.recv(1024).decode('utf-8') print(data_recv) if __name__ == "__main__": count = 0 for i in range(50): p = Process(target=client,args=('127.0.0.1',8000,str(i))) p.start() count += 1
人生苦短,我用cnblog