发布于 2015-08-30 08:00:38 | 159 次阅读 | 评论: 0 | 来源: 网络整理
An easy way to create a TCP server is to use the socketserver library. For example, here is a simple echo server:
from socketserver import BaseRequestHandler, TCPServer
print(‘Got connection from’, self.client_address) while True:
msg = self.request.recv(8192) if not msg:
breakself.request.send(msg)
In this code, you define a special handler class that implements a handle() method for servicing client connections. The request attribute is the underlying client socket and client_address has client address. To test the server, run it and then open a separate Python process that connects to it:
>>> from socket import socket, AF_INET, SOCK_STREAM
>>> s = socket(AF_INET, SOCK_STREAM)
>>> s.connect(('localhost', 20000))
>>> s.send(b'Hello')
5
>>> s.recv(8192)
b'Hello'
>>>
In many cases, it may be easier to define a slightly different kind of handler. Here is an example that uses the StreamRequestHandler base class to put a file-like interface on the underlying socket:
from socketserver import StreamRequestHandler, TCPServer
print(‘Got connection from’, self.client_address) # self.rfile is a file-like object for reading for line in self.rfile:
# self.wfile is a file-like object for writing self.wfile.write(line)
socketserver makes it relatively easy to create simple TCP servers. However, you should be aware that, by default, the servers are single threaded and can only serve one client at a time. If you want to handle multiple clients, either instantiate a ForkingTCP Server or ThreadingTCPServer object instead. For example:
from socketserver import ThreadingTCPServer ...
One issue with forking and threaded servers is that they spawn a new process or thread on each client connection. There is no upper bound on the number of allowed clients, so a malicious hacker could potentially launch a large number of simultaneous con‐ nections in an effort to make your server explode. If this is a concern, you can create a pre-allocated pool of worker threads or processes. To do this, you create an instance of a normal nonthreaded server, but then launch the serve_forever() method in a pool of multiple threads. For example:
... if __name__ == ‘__main__’:
from threading import Thread NWORKERS = 16 serv = TCPServer((‘’, 20000), EchoHandler) for n in range(NWORKERS):
t = Thread(target=serv.serve_forever) t.daemon = True t.start()serv.serve_forever()
Normally, a TCPServer binds and activates the underlying socket upon instantiation. However, sometimes you might want to adjust the underlying socket by setting options. To do this, supply the bind_and_activate=False argument, like this:
The socket option shown is actually a very common setting that allows the server to rebind to a previously used port number. It’s actually so common that it’s a class variable that can be set on TCPServer. Set it before instantiating the server, as shown in this example:
... if __name__ == ‘__main__’:
TCPServer.allow_reuse_address = True serv = TCPServer((‘’, 20000), EchoHandler) serv.serve_forever()
In the solution, two different handler base classes were shown (BaseRequestHandler and StreamRequestHandler). The StreamRequestHandler class is actually a bit more
flexible, and supports some features that can be enabled through the specification of additional class variables. For example:
import socket
# Optional settings (defaults shown) timeout = 5 # Timeout on all socket operations rbufsize = -1 # Read buffer size wbufsize = 0 # Write buffer size disable_nagle_algorithm = False # Sets TCP_NODELAY socket option def handle(self):
print(‘Got connection from’, self.client_address) try:
- for line in self.rfile:
- # self.wfile is a file-like object for writing self.wfile.write(line)
- except socket.timeout:
- print(‘Timed out!’)
Finally, it should be noted that most of Python’s higher-level networking modules (e.g., HTTP, XML-RPC, etc.) are built on top of the socketserver functionality. That said, it is also not difficult to implement servers directly using the socket library as well. Here is a simple example of directly programming a server with Sockets:
from socket import socket, AF_INET, SOCK_STREAM
print(‘Got connection from {}’.format(address)) while True:
msg = client_sock.recv(8192) if not msg:
breakclient_sock.sendall(msg)
client_sock.close()
sock = socket(AF_INET, SOCK_STREAM) sock.bind(address) sock.listen(backlog) while True:
client_sock, client_addr = sock.accept() echo_handler(client_addr, client_sock)