Python 创建TCP服务器的方法


Posted in Python onJuly 28, 2020

问题

你想实现一个服务器,通过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 相关文章推荐
python多线程threading.Lock锁用法实例
Nov 01 Python
详解Django框架中用context来解析模板的方法
Jul 20 Python
python实现解数独程序代码
Apr 12 Python
python Celery定时任务的示例
Mar 13 Python
Python二进制文件读取并转换为浮点数详解
Jun 25 Python
简单了解Python matplotlib线的属性
Jun 29 Python
selenium+Chrome滑动验证码破解二(某某网站)
Dec 17 Python
给 TensorFlow 变量进行赋值的方式
Feb 10 Python
python异常处理、自定义异常、断言原理与用法分析
Mar 23 Python
Python 解析简单的XML数据
Jul 24 Python
python如何导出微信公众号文章方法详解
Aug 31 Python
教你使用Python pypinyin库实现汉字转拼音
May 27 Python
Python实现画图软件功能方法详解
Jul 28 #Python
Python绘图之柱形图绘制详解
Jul 28 #Python
Python如何定义接口和抽象类
Jul 28 #Python
Python爬虫之爬取淘女郎照片示例详解
Jul 28 #Python
Python selenium键盘鼠标事件实现过程详解
Jul 28 #Python
用python写爬虫简单吗
Jul 28 #Python
公认8个效率最高的爬虫框架
Jul 28 #Python
You might like
thinkphp获取栏目和文章当前位置的方法
2014/10/29 PHP
php判断类是否存在函数class_exists用法分析
2014/11/14 PHP
PHP中实现接收多个name相同但Value不相同表单数据实例
2015/02/03 PHP
PHP实现的AES 128位加密算法示例
2019/09/16 PHP
Laravel框架源码解析之入口文件原理分析
2020/05/14 PHP
JavaScript Date对象 日期获取函数
2010/12/19 Javascript
javascript 构造函数强制调用经验总结
2012/12/02 Javascript
js动态创建表格,删除行列的小例子
2013/07/20 Javascript
jquery禁止回车触发表单提交
2014/12/12 Javascript
JavaScript动态修改网页元素内容的方法
2015/03/21 Javascript
JavaScript 表单处理实现代码
2015/04/13 Javascript
javascript实现实时输出当前的时间
2015/04/27 Javascript
JavaScript统计字符串中每个字符出现次数完整实例
2016/01/28 Javascript
详解BootStrap中Affix控件的使用及保持布局的美观的方法
2016/07/08 Javascript
谈谈JavaScript的New关键字
2016/08/26 Javascript
微信小程序 WXML、WXSS 和JS介绍及详解
2016/10/08 Javascript
Vue 仿百度搜索功能实现代码
2017/02/16 Javascript
详解Node.js开发中的express-session
2017/05/19 Javascript
axios的拦截请求与响应方法
2018/08/11 Javascript
ES6基础之解构赋值(destructuring assignment)
2019/02/21 Javascript
redux.js详解及基本使用
2019/05/24 Javascript
vue选项卡切换登录方式小案例
2019/09/27 Javascript
微信小程序 下拉刷新及上拉加载原理解析
2019/11/06 Javascript
vue router 传参获取不到的解决方式
2019/11/13 Javascript
详解Python中映射类型的内建函数和工厂函数
2015/08/19 Python
Django 实现购物车功能的示例代码
2018/10/08 Python
pycharm执行python时,填写参数的方法
2018/10/29 Python
浅析Python 字符编码与文件处理
2020/09/24 Python
使用pandas实现筛选出指定列值所对应的行
2020/12/13 Python
世界上最大的汽车共享网站:Zipcar
2017/01/14 全球购物
HelloFresh澳大利亚:订购你的美味食品盒、健康餐食
2018/03/28 全球购物
计算机专业大学生的自我评价
2013/11/14 职场文书
干部作风整顿自我剖析材料和整改措施
2014/09/18 职场文书
北大自主招生自荐信
2015/03/04 职场文书
材料采购员岗位职责
2015/04/03 职场文书
风雨哈佛路观后感
2015/06/03 职场文书