Socket 编程没有办法支持多并发用户;所以需要使用SocketServer 支持多并发。
socketserver一共有几种类型:
1、用Internet TCP协议,该协议在客户端和服务器之间提供连续的数据流。
class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
2、使用数据报(UDP协议),这些数据报是离散的信息包,可能无序到达或在运输途中丢失。参数与TCPServer相同。
class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
3、较少使用的类与TCP和UDP类相似,但使用Unix域套接字;它们在非Unix平台上不可用。参数与TCPServer相同。
class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True) class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)
继承上面的几种类,有五个类,其中四个代表四种类型的同步服务器
+------------+ | BaseServer | +------------+ | v +-----------+ +------------------+ | TCPServer |------->| UnixStreamServer | +-----------+ +------------------+ | v +-----------+ +--------------------+ | UDPServer |------->| UnixDatagramServer | +-----------+ +--------------------+
创建socketserver至少分以下几步:
1、First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests. 首先,您必须创建一个请求处理程序类,方法是继承BaseRequestHandler类并覆盖其handle()方法;此方法将处理传入的请求。 2、Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class. 其次,您必须实例化其中一个服务器类,并将其传递给服务器的地址和请求处理程序类 3、Then call the handle_request() orserve_forever() method of the server object to process one or many requests. 然后调用服务器对象的handle_request()or serve_forever()方法来处理一个或多个请求。注:一般用的比较多的是:serve_forever() 方法。 4、Finally, call server_close() to close the socket. 最后,调用server_close()关闭套接字。
简单实现单用户调用服务器端,客户端与服务器端实现交互。示例如下:
服务端:注意服务端的代码结构
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: self.data = self.request.recv(1024).strip() print ("{} write:".format(self.client_address[0])) print(self.data) self.request.send(self.data.upper()) except ConnectionResetError as e: print("err",e) break if __name__ == "__main__": HOST,PORT = "0.0.0.0",9999 #监听全网段 server = socketserver.TCPServer((HOST,PORT),MyTCPHandler) server.serve_forever()
客户端: 使用的是socket库
import socket client = socket.socket() client.connect(("200.62.5.3",9999)) while True: msg = input(">>:").strip() if msg == 0 : continue client.send(msg.encode("utf-8")) data = client.recv(1024) print("recv:",data.decode()) client.close()
输出:
客户端 # /opt/Python-3.5.2/python socketserver_clinet.py >>:ls recv: LS >>:fd recv: FD >>:fda recv: FDA >>:dfa recv: DFA >>:df recv: DF >>:d recv: D >>:a recv: A 服务端 # /opt/Python-3.5.2/python socketserver_server.py 200.62.5.3 write: b'ls' 200.62.5.3 write: b'fd' 200.62.5.3 write: b'fda' 200.62.5.3 write: b'dfa' 200.62.5.3 write: b'df' 200.62.5.3 write: b'd' 200.62.5.3 write: b'a'
让socketserver并发起来, 必须选择使用以下一个多并发的类
class socketserver.ForkingTCPServer class socketserver.ForkingUDPServer class socketserver.ThreadingTCPServer class socketserver.ThreadingUDPServer
针对上面简单的实例,要实行多并发,需要更改服务器端,客户端不变。操作如下:
只需要把下面这句
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
替换为下面的语法,就可以多并发。客户端每连进一个来,服务器端就会分配一个新的线程来处理这个客户端的请求
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
示例如下:
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: self.data = self.request.recv(1024).strip() print ("{} write:".format(self.client_address[0])) print(self.data) self.request.send(self.data.upper()) except ConnectionResetError as e: print("err",e) break if __name__ == "__main__": HOST,PORT = "0.0.0.0",9999 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) #调整了这句,建议以后代码上使用的都是这个多并发 server.serve_forever()
客户端代码不变,分别起三个客户端进行链接,测试如下:
第一个客户端: # /opt/Python-3.5.2/python socketserver_clinet.py >>:f recv: F 第二个客户端: # /opt/Python-3.5.2/python socketserver_clinet_2.py >>:chen recv: CHEN 第三个客户端: /Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/mac/PycharmProjects/untitled2/51CTO/6day/SocketServer_client.py >>:qing recv: QING 服务器端的接收: # /opt/Python-3.5.2/python socketserver_server.py 200.62.5.3 write: b'f' 200.62.5.3 write: b'chen' 101.38.8.11 write: b'qing'
备注:socketserver.ForkingTCPServer 与 socketserver.ThreadingTCPServer 都可以验证都可以实现多并发的需求。其实就是多进程与多线程的区别。ForkingTCPServer 在windows 不一定好用,liunxsh 基本上没有问题。后续,会仔细划分讲解。
1 class socketserver.BaseServer(server_address, RequestHandlerClass) 2 This is the superclass of all Server objects in the module. It defines the interface, given below, but does not implement most of the methods, which is done in subclasses. The two parameters are stored in the respective server_address and RequestHandlerClass attributes. 3 4 fileno() #文件描述符 5 Return an integer file descriptor for the socket on which the server is listening. This function is most commonly passed to selectors, to allow monitoring multiple servers in the same process. 6 7 handle_request() #处理单个请求 8 Process a single request. This function calls the following methods in order: get_request(), verify_request(), and process_request(). If the user-provided handle() method of the handler class raises an exception, the server’s handle_error() method will be called. If no request is received within timeout seconds, handle_timeout() will be called and handle_request() will return. 9 10 serve_forever(poll_interval=0.5) #清理僵死进程工作 11 Handle requests until an explicit shutdown() request. Poll for shutdown every poll_interval seconds. Ignores the timeout attribute. It also calls service_actions(), which may be used by a subclass or mixin to provide actions specific to a given service. For example, the ForkingMixIn class uses service_actions() to clean up zombie child processes. 12 13 Changed in version 3.3: Added service_actions call to the serve_forever method. 14 15 service_actions() #shutdown 会自动调用 16 This is called in the serve_forever() loop. This method can be overridden by subclasses or mixin classes to perform actions specific to a given service, such as cleanup actions. 17 18 New in version 3.3. 19 20 shutdown() 21 Tell the serve_forever() loop to stop and wait until it does. 22 23 server_close() #关闭 24 Clean up the server. May be overridden. 25 26 address_family #地址蔟 27 The family of protocols to which the server’s socket belongs. Common examples are socket.AF_INET and socket.AF_UNIX. 28 29 RequestHandlerClass 30 The user-provided request handler class; an instance of this class is created for each request. 31 32 server_address # 33 The address on which the server is listening. The format of addresses varies depending on the protocol family; see the documentation for the socket module for details. For Internet protocols, this is a tuple containing a string giving the address, and an integer port number: ('127.0.0.1', 80), for example. 34 35 socket 36 The socket object on which the server will listen for incoming requests. 37 38 The server classes support the following class variables: 39 40 allow_reuse_address 41 Whether the server will allow the reuse of an address. This defaults to False, and can be set in subclasses to change the policy. 42 43 request_queue_size 44 The size of the request queue. If it takes a long time to process a single request, any requests that arrive while the server is busy are placed into a queue, up to request_queue_size requests. Once the queue is full, further requests from clients will get a “Connection denied” error. The default value is usually 5, but this can be overridden by subclasses. 45 46 socket_type 47 The type of socket used by the server; socket.SOCK_STREAM and socket.SOCK_DGRAM are two common values. 48 49 timeout 50 Timeout duration, measured in seconds, or None if no timeout is desired. If handle_request() receives no incoming requests within the timeout period, the handle_timeout() method is called. 51 52 There are various server methods that can be overridden by subclasses of base server classes like TCPServer; these methods aren’t useful to external users of the server object. 53 54 finish_request() 55 Actually processes the request by instantiating RequestHandlerClass and calling its handle() method. 56 57 get_request() #获取请求的实例与IP地址 58 Must accept a request from the socket, and return a 2-tuple containing the new socket object to be used to communicate with the client, and the client’s address. 59 60 handle_error(request, client_address) 61 This function is called if the handle() method of a RequestHandlerClass instance raises an exception. The default action is to print the traceback to standard output and continue handling further requests. 62 63 handle_timeout() 64 This function is called when the timeout attribute has been set to a value other than None and the timeout period has passed with no requests being received. The default action for forking servers is to collect the status of any child processes that have exited, while in threading servers this method does nothing. 65 66 process_request(request, client_address) 67 Calls finish_request() to create an instance of the RequestHandlerClass. If desired, this function can create a new process or thread to handle the request; the ForkingMixIn and ThreadingMixIn classes do this. 68 69 server_activate() 70 Called by the server’s constructor to activate the server. The default behavior for a TCP server just invokes listen() on the server’s socket. May be overridden. 71 72 server_bind() 73 Called by the server’s constructor to bind the socket to the desired address. May be overridden. 74 75 verify_request(request, client_address) #判断请求是否合法 76 Must return a Boolean value; if the value is True, the request will be processed, and if it’s False, the request will be denied. This function can be overridden to implement access controls for a server. The default implementation always returns True.