python网络编程 socketserver模块
Posted 麦恒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python网络编程 socketserver模块相关的知识,希望对你有一定的参考价值。
1、socketserver模块
- socketserver是标准库中的一个高级模块(Python2.x中名为SocketServer)。
- socketserver的目标是简化创建网络客户端和服务器的代码。(隐藏了实现细节)
- socketserver是使用类来编写应用程序。
- 以面向对象的方式处理事务有助于组织数据,以及逻辑性地将功能放在正确的地方。应用程序现在是事件驱动的,这意味着只有在系统中的事件发生时,它们才会工作。
- socketserver中包含了两种类,一种为服务类(server class),一种为请求处理类(request handle class)。
- 服务类提供了许多方法:像绑定,监听,运行…… (也就是建立连接的过程)
- 请求处理类专注于如何处理用户所发送的数据(也就是事务逻辑)。
- socketserver模块是一个以socket为基础而创建的高级套接字通信模块,它支持客户端请求的多线程和多进程处理。
- 在原始服务器循环中,我们阻塞等待请求,当接收到请求时就对其提供服务,然后继续等待。
- 在socketserver的服务器循环中,并非在服务器中创建代码,而是定义一个处理程序,这样当服务器接收到一个传入的请求时,服务器就可以调用你的函数。
- socketserver模块类
1、服务类(同步处理请求)
- class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
- 它使用Internet TCP协议,该协议在客户机和服务器之间提供连续的数据流。
- 如果bind_and_activate为true,构造函数会自动尝试调用server_bind()和server_activate()。
- 其他参数传递给BaseServer基类。
- class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
- 它使用数据报,这是离散的信息包,可能会无序地到达或在传输中丢失。
- 参数与TCPServer相同。
-
class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)- 这两个不常用的类类似于TCP和UDP类,但使用Unix域套接字;它们在非unix平台上不可用。
- 参数与TCPServer相同。
-
这四个类同步处理请求;每个请求必须完成后才能启动下一个请求。
如果每个请求都需要很长时间才能完成,这是不合适的,因为它需要大量的计算,或者因为它返回大量的数据,而客户机处理起来很慢。
解决方案是每个请求都创建一个单独的进程或线程来处理;ForkingMixIn和ThreadingMixIn的混合类可以用来支持异步行为。 - 继承图中有五个类,其中四个表示四种类型的同步服务器
- 注意UnixDatagramServer派生于UDPServer,而不是UnixStreamServer --- IP和Unix流服务器之间的唯一区别是地址族,这只是在两个Unix服务器类中重复。
- 服务类具有相同的外部方法和属性,无论它们使用什么网络协议。
2、请求处理类
1、socketserver.BaseRequestHandler类
- 这是所有请求处理程序对象的超类。它定义了接口,如下所示。
- 一个具体的请求处理程序子类必须定义一个新的handle()方法,并且可以覆盖任何其他方法。
- 每个请求都会创建一个子类的新实例。
1、setup()方法
- 在handle()方法之前调用,以执行所需的任何初始化操作。默认什么也不做。
2、handle()方法
- 此方法必须完成为请求提供服务所需的所有工作。默认什么也不做。
- 它可以使用几个实例属性;请求是self.request;客户端地址是self.client_address;服务器实例是self.server,以防它需要访问每个服务器的信息。
- self.request的类型因数据报或流服务而不同。
- 对于流服务,self.request是客户端套接字对象;
- 对于数据报服务,self.request是一个双元组(客户端发送的数据, 客户端的套接字对象)。
3、finish()方法
- 在handle()方法之后调用,执行所需的任何清理操作。默认什么也不做。
- 如果setup()引发异常,则不会调用此函数。
2、socketserver模块的StreamRequestHandler类和DatagramRequestHandler类
- 这两个BaseRequestHandler子类覆盖了setup()和finish()方法,并提供了self.rfile和self.wfile属性。self.rfile和self.wfile分别读取或写入,以获取请求数据或将数据返回给客户机。
- 两个类的rfile属性都支持io.BufferedIOBase可读的接口,和DatagramRequestHandler.wfile支持io.BufferedIOBase可写接口。
- python3.6版:StreamRequestHandler.wfile也支持io.BufferedIOBase可写接口。
3、mix-in(混合)服务类(异步处理请求)
- 可以使用mix-in类创建每种类型基于进程(Forking)和线程(threading)的服务器。
- mix-in类:socketserver.ForkingMixIn类每次处理用户连接的时候都会开启新的进程。(多进程)
- mix-in类:socketserver.ThreadingMixIn类每次处理用户连接的时候都会开启新的线程。(多线程)
- 四种混合服务类
- mix-in类排在第一位,因为它覆盖了UDPServer中定义的方法。设置各种属性还会更改底层服务器机制的行为。
- ForkingMixIn和Forking类只在支持fork()的POSIX平台上可用。
#socketserver.ForkingTCPServer class ForkingTCPServer(ForkingMixIn, TCPServer): pass #socketserver.ForkingUDPServer class ForkingUDPServer(ForkingMixIn, UDPServer): pass #socketserver.ThreadingTCPServer class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass #socketserver.ThreadingUDPServer class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
- socketserver.ForkingMixIn.server_close()会等待所有子进程完成,除非socketserver.ForkingMixIn.block_on_close属性为false。
- socketserver.ThreadingMixIn.server_close()会等待所有非守护线程完成,除非socketserver.ThreadingMixIn.block_on_close属性为false。通过将ThreadingMixIn.daemon_threads设置为True来使用守护线程,这样就不会等待线程完成。
- python3.7:socketserver.ForkingMixIn.server_close()和socketserver.ThreadingMixIn.server_close()现在会等待所有子进程和非守护线程完成。添加一个新的socketserver.ForkingMixIn.block_on_close类属性来选择加入3.7之前的行为。
4、创建服务器需的步骤
- 创建一个请求处理类(request handler class),合理选择StreamRequestHandler和DatagramRequestHandler之中的一个作为父类(当然也可以使用BaseRequestHandler作为父类),并重写它的handle()方法,此方法将处理传入的请求。。
- 实例化一个服务类(server class)对象,并将服务器地址和之前创建的请求处理类传递给它。(建议在with语句中实例化服务类)
- 调用服务类对象的handle_request()或serve_forever()方法来处理一个或多个请求。
- 调用server_close()关闭套接字(除非使用with语句)。
- socketserver请求处理程序的默认行为是接受连接、获取请求,然后关闭连接。由于这个原因,我们不能在应用程序整个执行过程中都保持连接,因此每次向服务器发送消息时,都需要创建一个新的套接字。
2、服务类创建TCP服务器
1、python3创建TCP服务器和客户端
- 事件包括消息的发送和接收。事实上,类定义只包括一个用来接收客户端消息的事件处理程序。所有其他的功能都来自使用的SocketServer类。
- 最后一行代码通常是一个服务器的无限循环,它等待并响应客户端的服务请求。
示例1:实例化服务类时不使用with语句
- 创建SocketServer TCP服务器
- 多个客户端连接到服务器时,服务器只能按照客户端连接的顺序(即等待队列中的顺序)依次处理,否则将阻塞。
###python3.8 #!/usr/bin/env python from socketserver import (TCPServer as TCP, StreamRequestHandler as SRH) from time import ctime HOST = \'\' PORT = 21567 ADDR = (HOST, PORT) class MyRequesHandler(SRH): #创建一个请求处理类 def handle(self): #重写handle()方法 self.data = str(self.request.recv(1024).strip(), \'utf8\') #接收客户端发来的数据 print(\'...connected from:\', self.client_address) print(self.data) self.request.sendall(bytes(\'%s %s\' % (self.data, ctime()), \'utf8\')) #处理数据,并发送给客户端 TCP.request_queue_size = 10 #默认等待队列中可以有5个客户端,即最大可以连接6个客户端,request_queue_size = 5 tcpServ = TCP(ADDR, MyRequesHandler) #实例化一个服务类对象。会创建一个套接字,并绑定地址和监听 print(\'waiting for connection...\') tcpServ.serve_forever() #处理客户端发来的请求,其实就是调用handle()方法
- 创建SocketServer TCP客户端
###python3.8 #!/usr/bin/env python from socket import * HOST = \'localhost\' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) while True: tcpClisock = socket(AF_INET, SOCK_STREAM) tcpClisock.connect(ADDR) data = input(\'> \') if not data: break tcpClisock.send(bytes(data,\'utf8\')) data = tcpClisock.recv(BUFSIZ) if not data: break print(str(data.strip(),\'utf8\')) tcpClisock.close()
示例2:实例化服务类时使用with语句
- 创建SocketServer TCP服务器
- 多个客户端连接到服务器时,服务器只能按照客户端连接的顺序(即等待队列中的顺序)依次处理,否则将阻塞。
###python3.8 #!/usr/bin/env python import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 21567 with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server: server.serve_forever()
- 创建SocketServer TCP客户端
###python3.8 #!/usr/bin/env python import socket import sys HOST, PORT = "localhost", 21567 while True: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect((HOST, PORT)) data = input(\'>\') if not data: break sock.sendall(bytes(data + "\\n", "utf-8")) received = str(sock.recv(1024), "utf-8") print("Sent: {}".format(data)) print("Received: {}".format(received))
2、python2创建TCP服务器和客户端
- 创建SocketServer TCP服务器
###python2.7 #!/usr/bin/env python from SocketServer import (TCPServer as TCP, StreamRequestHandler as SRH) from time import ctime HOST = \'\' PORT = 21567 ADDR = (HOST, PORT) class MyRequesHandler(SRH): def handle(self): print \'...connected from:\',self.client_address self.wfile.write(\'[%s] %s\' % (ctime(), self.rfile.readline())) tcpServ = TCP(ADDR, MyRequesHandler) print \'waiting for connection...\' tcpServ.serve_forever()
- 创建SocketServer TCP客户端
###python2.7 #!/usr/bin/env python from socket import * HOST = \'localhost\' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) while True: tcpClisock = socket(AF_INET, SOCK_STREAM) tcpClisock.connect(ADDR) data = raw_input(\'> \') if not data: break tcpClisock.send(\'%s\\r\\n\' % data) data = tcpClisock.recv(BUFSIZ) if not data: break print data.strip() tcpClisock.close()
3、服务类创建UDP服务器
- 创建SocketServer UDP服务器
- 多个客户端连接到服务器时,服务器收到一个请求处理一个请求,不会阻塞。
###python3.8 #!/usr/bin/env python import socketserver class MyUDPHandler(socketserver.BaseRequestHandler): def handle(self): #print(self.request) #(b\'221\\n\', <socket.socket fd=428, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=(\'127.0.0.1\', 21567)>) data = self.request[0].strip() socket = self.request[1] print("{} wrote:".format(self.client_address[0])) print(data) socket.sendto(data.upper(), self.client_address) if __name__ == "__main__": HOST, PORT = "localhost", 21567 with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server: server.serve_forever()
- 创建SocketServer UDP客户端
###python3.8 #!/usr/bin/env python import socket HOST, PORT = "localhost", 21567 while True: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) data = input(\'> \') if not data: break sock.sendto(bytes(data + "\\n", "utf-8"), (HOST, PORT)) received = str(sock.recv(1024), "utf-8") print("Sent: {}".format(data)) print("Received: {}".format(received))
4、mix-in(混合)类创建TCP服务器
1、多线程处理请求(ThreadingMixIn类)
- 创建SocketServer TCP服务器
- 多个客户端连接到服务器时,客户端的每个请求服务器都会新创建一个线程进行处理。
###python3.8 #!/usr/bin/env python import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 21567 with socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) as server: #与同步的相比,几乎没有变化,除了服务类使用了ThreadingTCPServer类 server.serve_forever()
- 创建SocketServer TCP客户端
###python3.8 #!/usr/bin/env python from socket import * HOST = \'localhost\' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) while True: tcpClisock = socket(AF_INET, SOCK_STREAM) tcpClisock.connect(ADDR) data = input(\'> \') if not data: break tcpClisock.send(bytes(data, \'utf8\')) data = tcpClisock.recv(BUFSIZ) if not data: break print(str(data.strip(), \'utf8\')) tcpClisock.close()
2、多进程处理请求(ForkingMixIn类)
- 创建SocketServer TCP服务器
- 多个客户端连接到服务器时,客户端的每个请求服务器都会新创建一个进程进行处理。
- 特别注意:必须运行在unix上。因为Windows不支持fork(),所以ForkingMixIn类在Windows上不可用。
#!/usr/bin/env python import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = \'192.168.248.128\', 21567 with socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler) as server: #与同步的相比,几乎没有变化,除了服务类使用了ForkingTCPServer类 server.serve_forever()
- 创建SocketServer TCP客户端
###python3.8 #!/usr/bin/env python from socket import * HOST = \'192.168.248.128\' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) while True: tcpClisock = socket(AF_INET, SOCK_STREAM) tcpClisock.connect(ADDR) data = input(\'> \') if not data: break tcpClisock.send(bytes(data, \'utf8\')) data = tcpClisock.recv(BUFSIZ) if not data: break print(str(data.strip(), \'utf8\')) tcpClisock.close()
5、mix-in(混合)类创建UDP服务器
1、多线程处理请求(ThreadingMixIn类)
- 创建SocketServer UDP服务器
###python3.8 #!/usr/bin/env python import socketserver class MyUDPHandler(socketserver.BaseRequestHandler): def handle(self): #print(self.request) data = self.request[0].strip() socket = self.request[1] print("{} wrote:".format(self.client_address[0])) print(data) socket.sendto(data.upper(), self.client_address) if __name__ == "__main__": HOST, PORT = "localhost", 21567 with socketserver.ThreadingUDPServer((HOST, PORT), MyUDPHandler) as server: #区别仅在于服务类是ThreadingUDPServer server.serve_forever()
- 创建SocketServer UDP客户端
###python3.8 #!/usr/bin/env python import socket HOST, PORT = "localhost", 21567 while True: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) data = input(\'> \') if not data: break sock.sendto(bytes(data + "\\n", "utf-8"), (HOST, PORT)) received = str(sock.recv(1024), "utf-8") print("Sent: {}".format(data)) print("Received: {}".format(received))
2、多进程处理请求(ForkingMixIn类)
- 创建SocketServer UDP服务器
- 特别注意:必须运行在unix上。因为Windows不支持fork(),所以ForkingMixIn类在Windows上不可用。
#!/usr/bin/env python import socketserver class MyUDPHandler(socketserver.BaseRequestHandler): def handle(self): #print(self.request) data = self.request[0].strip() socket = self.request[1] print("{} wrote:".format(self.client_address[0])) print(data) socket.sendto(data.upper(), self.client_address) if __name__ == "__main__": HOST, PORT = \'192.168.248.128\', 21567 with socketserver.ForkingUDPServer((HOST, PORT), MyUDPHandler) as server: #区别仅在于服务类是ForkingUDPServer server.serve_forever()
- 创建SocketServer UDP客户端
###python3.8 # !/usr/bin/env python import socket HOST, PORT = \'192.168.248.128\', 21567 while True: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) data = input(\'> \') if not data: break sock.sendto(bytes(data + "\\n", "utf-8"), (HOST, PORT)) received = str(sock.recv(1024), "utf-8") print("Sent: {}".format(data)) print("Received: {}".format(received))
以上是关于python网络编程 socketserver模块的主要内容,如果未能解决你的问题,请参考以下文章
python模块介绍- SocketServer 网络服务框架
Python3-socketserver模块-网络服务器框架