SocketServer 网络服务框架

SocketServer简化了网络服务器的编写。它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。这4个类是同步进行处理的,另外通过ForkingMixIn和ThreadingMixIn类来支持异步。

创建服务器的步骤。首先,你必须创建一个请求处理类,它是BaseRequestHandler的子类并重载其handle()方法。其次,你必须实例化一个服务器类,传入服务器的地址和请求处理程序类。最后,调用handle_request()(一般是调用其他事件循环或者使用select())或serve_forever()。

集成ThreadingMixIn类时需要处理异常关闭。daemon_threads指示服务器是否要等待线程终止,要是线程互相独立,必须要设置为True,默认是False。

无论用什么网络协议,服务器类有相同的外部方法和属性。

该模块在python3中已经更名为socketserver。

服务器类型

5种类型:BaseServer,TCPServer,UnixStreamServer,UDPServer,UnixDatagramServer。 注意:BaseServer不直接对外服务。

服务器对象

  • class SocketServer.BaseServer:这是模块中的所有服务器对象的超类。它定义了接口,如下所述,但是大多数的方法不实现,在子类中进行细化。

  • BaseServer.fileno():返回服务器监听套接字的整数文件描述符。通常用来传递给select.select(), 以允许一个进程监视多个服务器。

  • BaseServer.handle_request():处理单个请求。处理顺序:get_request(), verify_request(), process_request()。如果用户提供handle()方法抛出异常,将调用服务器的handle_error()方法。如果self.timeout内没有请求收到, 将调用handle_timeout()并返回handle_request()。

  • BaseServer.serve_forever(poll_interval=0.5): 处理请求,直到一个明确的shutdown()请求。每poll_interval秒轮询一次shutdown。忽略self.timeout。如果你需要做周期性的任务,建议放置在其他线程。

  • BaseServer.shutdown():告诉serve_forever()循环停止并等待其停止。python2.6版本。

  • BaseServer.address_family: 地址家族,比如socket.AF_INET和socket.AF_UNIX。

  • BaseServer.RequestHandlerClass:用户提供的请求处理类,这个类为每个请求创建实例。

  • BaseServer.server_address:服务器侦听的地址。格式根据协议家族地址的各不相同,请参阅socket模块的文档。

  • BaseServer.socketSocket:服务器上侦听传入的请求socket对象的服务器。

服务器类支持下面的类变量:

  • BaseServer.allow_reuse_address:服务器是否允许地址的重用。默认为false ,并且可在子类中更改。

  • BaseServer.request_queue_size

请求队列的大小。如果单个请求需要很长的时间来处理,服务器忙时请求被放置到队列中,最多可以放request_queue_size个。一旦队列已满,来自客户端的请求将得到 “Connection denied”错误。默认值通常为5 ,但可以被子类覆盖。

  • BaseServer.socket_type:服务器使用的套接字类型; socket.SOCK_STREAM和socket.SOCK_DGRAM等。

  • BaseServer.timeout:超时时间,以秒为单位,或 None表示没有超时。如果handle_request()在timeout内没有收到请求,将调用handle_timeout()。

下面方法可以被子类重载,它们对服务器对象的外部用户没有影响。

  • BaseServer.finish_request():实际处理RequestHandlerClass发起的请求并调用其handle()方法。 常用。

  • BaseServer.get_request():接受socket请求,并返回二元组包含要用于与客户端通信的新socket对象,以及客户端的地址。

  • BaseServer.handle_error(request, client_address):如果RequestHandlerClass的handle()方法抛出异常时调用。默认操作是打印traceback到标准输出,并继续处理其他请求。

  • BaseServer.handle_timeout():超时处理。默认对于forking服务器是收集退出的子进程状态,threading服务器则什么都不做。

  • BaseServer.process_request(request, client_address) :调用finish_request()创建RequestHandlerClass的实例。如果需要,此功能可以创建新的进程或线程来处理请求,ForkingMixIn和ThreadingMixIn类做到这点。常用。

  • BaseServer.server_activate():通过服务器的构造函数来激活服务器。默认的行为只是监听服务器套接字。可重载。

  • BaseServer.server_bind():通过服务器的构造函数中调用绑定socket到所需的地址。可重载。

  • BaseServer.verify_request(request, client_address):返回一个布尔值,如果该值为True ,则该请求将被处理,反之请求将被拒绝。此功能可以重写来实现对服务器的访问控制。默认的实现始终返回True。client_address可以限定客户端,比如只处理指定ip区间的请求。 常用。

请求处理器

处理器接收数据并决定如何操作。它负责在socket层之上实现协议(i.e., HTTP, XML-RPC, or AMQP),读取数据,处理并写反应。可以重载的方法如下:

  • setup(): 准备请求处理. 默认什么都不做,StreamRequestHandler中会创建文件类似的对象以读写socket.

  • handle(): 处理请求。解析传入的请求,处理数据,并发送响应。默认什么都不做。常用变量:self.request,self.client_address,self.server。

  • finish(): 环境清理。默认什么都不做,如果setup产生异常,不会执行finish。

通常只需要重载handle。self.request的类型和数据报或流的服务不同。对于流服务,self.request是socket 对象;对于数据报服务,self.request是字符串和socket 。可以在子类StreamRequestHandler或DatagramRequestHandler中重载,重写setup()和finish() ,并提供self.rfile和self.wfile属性。 self.rfile和self.wfile可以读取或写入,以获得请求数据或将数据返回到客户端。

Echo实例

TCPServer

TCPServer.py

 1 import SocketServerclass MyTCPHandler(SocketServer.BaseRequestHandler):
 2     """
 3     The RequestHandler class for our server.
 4 
 5     It is instantiated once per connection to the server, and must
 6     override the handle() method to implement communication to the
 7     client.
 8     """
 9 
10     def handle(self):
11         # self.request is the TCP socket connected to the client
12         self.data = self.request.recv(1024).strip()
13         print "{} wrote:".format(self.client_address[0])
14         print self.data        # just send back the same data, but upper-cased
15         self.request.sendall(self.data.upper())if __name__ == "__main__":
16     HOST, PORT = "localhost", 9999
17 
18     # Create the server, binding to localhost on port 9999
19     server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
20 
21     # Activate the server; this will keep running until you
22     # interrupt the program with Ctrl-C
23     server.serve_forever()

 

另外一种方式是使用流,一次读一行。

 1 class MyTCPHandler(SocketServer.StreamRequestHandler):
 2 
 3     def handle(self):
 4         # self.rfile is a file-like object created by the handler;
 5         # we can now use e.g. readline() instead of raw recv() calls
 6         self.data = self.rfile.readline().strip()
 7         print "{} wrote:".format(self.client_address[0])
 8         print self.data        # Likewise, self.wfile is a file-like object used to write back
 9         # to the client
10         self.wfile.write(self.data.upper())
 

客户端:

1 import socketimport sysHOST, PORT = "localhost", 9999data = " ".join(sys.argv[1:])# Create a socket (SOCK_STREAM means a TCP socket)sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:
2     # Connect to server and send data
3     sock.connect((HOST, PORT))
4     sock.sendall(data + "\n")
5 
6     # Receive data from the server and shut down
7     received = sock.recv(1024)finally:
8     sock.close()print "Sent:     {}".format(data)print "Received: {}".format(received)
 

《The Python Standard Library by Example 2011》有更详细的echo实例,参见11.3.5部分。 执行结果:

th
 1 # python TCPServer.py 
 2 127.0.0.1 wrote:
 3 hello world with TCP
 4 127.0.0.1 wrote:
 5 python is nice# python TCPClient.py 
 6 Sent:     
 7 Received: 
 8 # python TCPClient.py hello world with TCPSent:     hello world with TCP
 9 Received: HELLO WORLD WITH TCP# python TCPClient.py python is niceSent:     python is nice
10 Received: PYTHON IS NICE
 

UDPServer

UDPServer.py

 1 import SocketServerclass MyUDPHandler(SocketServer.BaseRequestHandler):
 2     """
 3     This class works similar to the TCP handler class, except that
 4     self.request consists of a pair of data and client socket, and since
 5     there is no connection the client address must be given explicitly
 6     when sending data back via sendto().
 7     """
 8 
 9     def handle(self):
10         data = self.request[0].strip()
11         socket = self.request[1]
12         print "{} wrote:".format(self.client_address[0])
13         print data
14         socket.sendto(data.upper(), self.client_address)if __name__ == "__main__":
15     HOST, PORT = "localhost", 9999
16     server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)
17     server.serve_forever()
 

UDPClient.py

1 import socketimport sysHOST, PORT = "localhost", 9999data = " ".join(sys.argv[1:])# SOCK_DGRAM is the socket type to use for UDP socketssock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# As you can see, there is no connect() call; UDP has no connections.# Instead, data is directly sent to the recipient via sendto().sock.sendto(data + "\n", (HOST, PORT))received = sock.recv(1024)print "Sent:     {}".format(data)print "Received: {}".format(received)
执行和UDP类似。

异步

ThreadingMixIn的例子:

  1 磁针石的个人空间  工作日志  正文
  2 
  3 python模块介绍- SocketServer 网络服务框架 原 荐
  4  磁针石   磁针石 发布于 2014/01/06 07:04 字数 2163 阅读 45109 收藏 57 点赞 5  评论 3
  5 python模块SocketServer网络服务框架
  6 华为云开发者4大福利:2核4G云主机、DevCloud、应用服务、培训课程 免费领取 >>>   
  7 
  8 SocketServer简化了网络服务器的编写。它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。这4个类是同步进行处理的,另外通过ForkingMixIn和ThreadingMixIn类来支持异步。
  9 
 10 创建服务器的步骤。首先,你必须创建一个请求处理类,它是BaseRequestHandler的子类并重载其handle()方法。其次,你必须实例化一个服务器类,传入服务器的地址和请求处理程序类。最后,调用handle_request()(一般是调用其他事件循环或者使用select())或serve_forever()。
 11 
 12 集成ThreadingMixIn类时需要处理异常关闭。daemon_threads指示服务器是否要等待线程终止,要是线程互相独立,必须要设置为True,默认是False。
 13 
 14 无论用什么网络协议,服务器类有相同的外部方法和属性。
 15 
 16 该模块在python3中已经更名为socketserver。
 17 
 18 服务器类型
 19 5种类型:BaseServer,TCPServer,UnixStreamServer,UDPServer,UnixDatagramServer。 注意:BaseServer不直接对外服务。
 20 
 21 服务器对象
 22 class SocketServer.BaseServer:这是模块中的所有服务器对象的超类。它定义了接口,如下所述,但是大多数的方法不实现,在子类中进行细化。
 23 
 24 BaseServer.fileno():返回服务器监听套接字的整数文件描述符。通常用来传递给select.select(), 以允许一个进程监视多个服务器。
 25 
 26 BaseServer.handle_request():处理单个请求。处理顺序:get_request(), verify_request(), process_request()。如果用户提供handle()方法抛出异常,将调用服务器的handle_error()方法。如果self.timeout内没有请求收到, 将调用handle_timeout()并返回handle_request()。
 27 
 28 BaseServer.serve_forever(poll_interval=0.5): 处理请求,直到一个明确的shutdown()请求。每poll_interval秒轮询一次shutdown。忽略self.timeout。如果你需要做周期性的任务,建议放置在其他线程。
 29 
 30 BaseServer.shutdown():告诉serve_forever()循环停止并等待其停止。python2.6版本。
 31 
 32 BaseServer.address_family: 地址家族,比如socket.AF_INET和socket.AF_UNIX。
 33 
 34 BaseServer.RequestHandlerClass:用户提供的请求处理类,这个类为每个请求创建实例。
 35 
 36 BaseServer.server_address:服务器侦听的地址。格式根据协议家族地址的各不相同,请参阅socket模块的文档。
 37 
 38 BaseServer.socketSocket:服务器上侦听传入的请求socket对象的服务器。
 39 
 40 服务器类支持下面的类变量:
 41 
 42 BaseServer.allow_reuse_address:服务器是否允许地址的重用。默认为false ,并且可在子类中更改。
 43 
 44 BaseServer.request_queue_size
 45 
 46 请求队列的大小。如果单个请求需要很长的时间来处理,服务器忙时请求被放置到队列中,最多可以放request_queue_size个。一旦队列已满,来自客户端的请求将得到 “Connection denied”错误。默认值通常为5 ,但可以被子类覆盖。
 47 
 48 BaseServer.socket_type:服务器使用的套接字类型; socket.SOCK_STREAM和socket.SOCK_DGRAM等。
 49 
 50 BaseServer.timeout:超时时间,以秒为单位,或 None表示没有超时。如果handle_request()在timeout内没有收到请求,将调用handle_timeout()。
 51 
 52 下面方法可以被子类重载,它们对服务器对象的外部用户没有影响。
 53 
 54 BaseServer.finish_request():实际处理RequestHandlerClass发起的请求并调用其handle()方法。 常用。
 55 
 56 BaseServer.get_request():接受socket请求,并返回二元组包含要用于与客户端通信的新socket对象,以及客户端的地址。
 57 
 58 BaseServer.handle_error(request, client_address):如果RequestHandlerClass的handle()方法抛出异常时调用。默认操作是打印traceback到标准输出,并继续处理其他请求。
 59 
 60 BaseServer.handle_timeout():超时处理。默认对于forking服务器是收集退出的子进程状态,threading服务器则什么都不做。
 61 
 62 BaseServer.process_request(request, client_address) :调用finish_request()创建RequestHandlerClass的实例。如果需要,此功能可以创建新的进程或线程来处理请求,ForkingMixIn和ThreadingMixIn类做到这点。常用。
 63 
 64 BaseServer.server_activate():通过服务器的构造函数来激活服务器。默认的行为只是监听服务器套接字。可重载。
 65 
 66 BaseServer.server_bind():通过服务器的构造函数中调用绑定socket到所需的地址。可重载。
 67 
 68 BaseServer.verify_request(request, client_address):返回一个布尔值,如果该值为True ,则该请求将被处理,反之请求将被拒绝。此功能可以重写来实现对服务器的访问控制。默认的实现始终返回True。client_address可以限定客户端,比如只处理指定ip区间的请求。 常用。
 69 
 70 请求处理器
 71 处理器接收数据并决定如何操作。它负责在socket层之上实现协议(i.e., HTTP, XML-RPC, or AMQP),读取数据,处理并写反应。可以重载的方法如下:
 72 
 73 setup(): 准备请求处理. 默认什么都不做,StreamRequestHandler中会创建文件类似的对象以读写socket.
 74 
 75 handle(): 处理请求。解析传入的请求,处理数据,并发送响应。默认什么都不做。常用变量:self.request,self.client_address,self.server。
 76 
 77 finish(): 环境清理。默认什么都不做,如果setup产生异常,不会执行finish。
 78 
 79 通常只需要重载handle。self.request的类型和数据报或流的服务不同。对于流服务,self.request是socket 对象;对于数据报服务,self.request是字符串和socket 。可以在子类StreamRequestHandler或DatagramRequestHandler中重载,重写setup()和finish() ,并提供self.rfile和self.wfile属性。 self.rfile和self.wfile可以读取或写入,以获得请求数据或将数据返回到客户端。
 80 
 81 Echo实例
 82 TCPServer
 83 TCPServer.py
 84 
 85 import SocketServerclass MyTCPHandler(SocketServer.BaseRequestHandler):
 86     """
 87     The RequestHandler class for our server.
 88 
 89     It is instantiated once per connection to the server, and must
 90     override the handle() method to implement communication to the
 91     client.
 92     """
 93 
 94     def handle(self):
 95         # self.request is the TCP socket connected to the client
 96         self.data = self.request.recv(1024).strip()
 97         print "{} wrote:".format(self.client_address[0])
 98         print self.data        # just send back the same data, but upper-cased
 99         self.request.sendall(self.data.upper())if __name__ == "__main__":
100     HOST, PORT = "localhost", 9999
101 
102     # Create the server, binding to localhost on port 9999
103     server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
104 
105     # Activate the server; this will keep running until you
106     # interrupt the program with Ctrl-C
107     server.serve_forever()
108 另外一种方式是使用流,一次读一行。
109 
110 class MyTCPHandler(SocketServer.StreamRequestHandler):
111 
112     def handle(self):
113         # self.rfile is a file-like object created by the handler;
114         # we can now use e.g. readline() instead of raw recv() calls
115         self.data = self.rfile.readline().strip()
116         print "{} wrote:".format(self.client_address[0])
117         print self.data        # Likewise, self.wfile is a file-like object used to write back
118         # to the client
119         self.wfile.write(self.data.upper())
120 客户端:
121 
122 import socketimport sysHOST, PORT = "localhost", 9999data = " ".join(sys.argv[1:])# Create a socket (SOCK_STREAM means a TCP socket)sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:
123     # Connect to server and send data
124     sock.connect((HOST, PORT))
125     sock.sendall(data + "\n")
126 
127     # Receive data from the server and shut down
128     received = sock.recv(1024)finally:
129     sock.close()print "Sent:     {}".format(data)print "Received: {}".format(received)
130 《The Python Standard Library by Example 2011》有更详细的echo实例,参见11.3.5部分。 执行结果:
131 
132 # python TCPServer.py 
133 127.0.0.1 wrote:
134 hello world with TCP
135 127.0.0.1 wrote:
136 python is nice# python TCPClient.py 
137 Sent:     
138 Received: 
139 # python TCPClient.py hello world with TCPSent:     hello world with TCP
140 Received: HELLO WORLD WITH TCP# python TCPClient.py python is niceSent:     python is nice
141 Received: PYTHON IS NICE
142 UDPServer
143 UDPServer.py
144 
145 import SocketServerclass MyUDPHandler(SocketServer.BaseRequestHandler):
146     """
147     This class works similar to the TCP handler class, except that
148     self.request consists of a pair of data and client socket, and since
149     there is no connection the client address must be given explicitly
150     when sending data back via sendto().
151     """
152 
153     def handle(self):
154         data = self.request[0].strip()
155         socket = self.request[1]
156         print "{} wrote:".format(self.client_address[0])
157         print data
158         socket.sendto(data.upper(), self.client_address)if __name__ == "__main__":
159     HOST, PORT = "localhost", 9999
160     server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)
161     server.serve_forever()
162 UDPClient.py
163 
164 import socketimport sysHOST, PORT = "localhost", 9999data = " ".join(sys.argv[1:])# SOCK_DGRAM is the socket type to use for UDP socketssock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# As you can see, there is no connect() call; UDP has no connections.# Instead, data is directly sent to the recipient via sendto().sock.sendto(data + "\n", (HOST, PORT))received = sock.recv(1024)print "Sent:     {}".format(data)print "Received: {}".format(received)
165 执行和UDP类似。
166 
167 异步
168 ThreadingMixIn的例子:
169 
170 import socketimport threadingimport SocketServerclass ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
171 
172     def handle(self):
173         data = self.request.recv(1024)
174         cur_thread = threading.current_thread()
175         response = "{}: {}".format(cur_thread.name, data)
176         self.request.sendall(response)class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
177     passdef client(ip, port, message):
178     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
179     sock.connect((ip, port))
180     try:
181         sock.sendall(message)
182         response = sock.recv(1024)
183         print "Received: {}".format(response)
184     finally:
185         sock.close()if __name__ == "__main__":
186     # Port 0 means to select an arbitrary unused port
187     HOST, PORT = "localhost", 0
188 
189     server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
190     ip, port = server.server_address    # Start a thread with the server -- that thread will then start one
191     # more thread for each request
192     server_thread = threading.Thread(target=server.serve_forever)
193     # Exit the server thread when the main thread terminates
194     server_thread.daemon = True
195     server_thread.start()
196     print "Server loop running in thread:", server_thread.name
197 
198     client(ip, port, "Hello World 1")
199     client(ip, port, "Hello World 2")
200     client(ip, port, "Hello World 3")
201 
202     server.shutdown()
 

执行结果:

 1 $ python ThreadedTCPServer.py 2 Server loop running in thread: Thread-1 3 Received: Thread-2: Hello World 1 4 Received: Thread-3: Hello World 2 5 Received: Thread-4: Hello World 3 

ForkingMixIn的使用方法类似,只不过是用进程代替了线程。《The Python Standard Library by Example 2011》中有相关实例。

猜你喜欢

转载自www.cnblogs.com/randomlee/p/9252812.html