Python 创建TCP服务器的方法

Ivy
Ivy
发布时间:2026-10-14 | 5人浏览过
原创

本文介绍如何使用Python的socketserver库创建TCP服务器。通过BaseRequestHandler和StreamRequestHandler实现基本通信,并讨论多线程、进程池处理并发连接及端口复用配置,最后展示基于socket库的低级实现。

Python 创建TCP服务器的方法

问题

你需要构建一个服务器,使其能够通过TCP协议与客户端进行数据通信。

解决方案

构建TCP服务器的一种简便方式是利用socketserver模块。以下示例展示了一个基础的应答服务器实现:


from socketserver import BaseRequestHandler, TCPServer

class EchoHandler(BaseRequestHandler):
  def handle(self):
    print('Got connection from', self.client_address)
    while True:

      msg = self.request.recv(8192)
      if not msg:
        break
      self.request.send(msg)

if __name__ == '__main__':
  serv = TCPServer(('', 20000), EchoHandler)
  serv.serve_forever()

在该代码片段中,你定义了一个特定的处理类,其中实现了handle()方法以响应客户端连接。request属性代表客户端的socket对象,而client_address则存储了客户端的地址信息。为了测试该服务器,请运行代码并启动另一个Python进程来连接此服务器:


>>> 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'
>>>

在实际应用中,定义不同的处理器往往更加便捷。下面是一个使用StreamRequestHandler基类的示例,它为底层socket提供了一个类文件接口:


from socketserver import StreamRequestHandler, TCPServer

class EchoHandler(StreamRequestHandler):
  def handle(self):
    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)

if __name__ == '__main__':
  serv = TCPServer(('', 20000), EchoHandler)
  serv.serve_forever()

讨论

socketserver模块使得创建简单的TCP服务器变得容易。然而,需要注意的是,默认情况下该服务器是单线程的,这意味着它一次只能为一个客户端连接提供服务。若需同时处理多个客户端,可以初始化ForkingTCPServer或ThreadingTCPServer对象。例如:


from socketserver import ThreadingTCPServer


if __name__ == '__main__':
  serv = ThreadingTCPServer(('', 20000), EchoHandler)
  serv.serve_forever()

使用fork或线程服务器存在一个潜在问题,即为每个客户端连接创建一个新的进程或线程。由于客户端连接数通常没有限制,恶意黑客可能通过发送大量连接导致服务器崩溃。

若担心此问题,可以创建一个预先分配大小的工作线程池或进程池。首先创建一个普通的非线程服务器,然后在一个线程池中使用serve_forever()方法来启动它们:


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()

通常情况下,TCPServer在实例化时会绑定并激活相应的socket。但有时你需要通过设置某些选项来调整底层socket,可以设置参数bind_and_activate=False。具体如下:


if __name__ == '__main__':
  serv = TCPServer(('', 20000), EchoHandler, bind_and_activate=False)
  # Set up various socket options
  serv.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
  # Bind and activate
  serv.server_bind()
  serv.server_activate()
  serv.serve_forever()

上述socket选项是一个常见的配置项,它允许服务器重新绑定之前使用过的端口号。由于该选项使用频繁,它被放置在类变量中,可以直接在TCPServer上设置。在实例化服务器时设置其值,如下所示:


if __name__ == '__main__':
  TCPServer.allow_reuse_address = True
  serv = TCPServer(('', 20000), EchoHandler)
  serv.serve_forever()

在上面的示例中,我们演示了两种不同的处理器基类(BaseRequestHandler和StreamRequestHandler)。StreamRequestHandler更加灵活,能通过设置其他类变量来支持一些新特性。例如:


import socket

class EchoHandler(StreamRequestHandler):
  # 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!')

最后,还需注意绝大部分Python的高层网络模块(如HTTP、XML-RPC等)都是建立在socketserver功能之上。也就是说,直接使用socket库来实现服务器也并不是很难。以下是一个使用socket直接编程实现的服务器简单例子:


from socket import socket, AF_INET, SOCK_STREAM

def echo_handler(address, client_sock):
  print('Got connection from {}'.format(address))
  while True:
    msg = client_sock.recv(8192)
    if not msg:
      break
    client_sock.sendall(msg)
  client_sock.close()

def echo_server(address, backlog=5):
  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)

if __name__ == '__main__':
  echo_server(('', 20000))

以上就是Python 创建TCP服务器的方法的详细内容,更多关于Python 创建TCP服务器的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表