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(一)Python环境安装
Aug 20 Python
Python中使用装饰器时需要注意的一些问题
May 11 Python
tensorflow入门之训练简单的神经网络方法
Feb 26 Python
python 获取utc时间转化为本地时间的方法
Dec 31 Python
Python txt文件加入字典并查询的方法
Jan 15 Python
python实现AES加密与解密
Mar 28 Python
Python利用WMI实现ping命令的例子
Aug 14 Python
python生成器推导式用法简单示例
Oct 08 Python
使用pandas的box_plot去除异常值
Dec 10 Python
Python命令行参数定义及需要注意的地方
Nov 30 Python
pytorch中F.avg_pool1d()和F.avg_pool2d()的使用操作
May 22 Python
python opencv检测直线 cv2.HoughLinesP的实现
Jun 18 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
第十三节--对象串行化
2006/11/16 PHP
UTF8编码内的繁简转换的PHP类
2009/07/09 PHP
解析PHP中的unset究竟会不会释放内存
2013/07/18 PHP
PHP函数in_array()使用详解
2014/08/20 PHP
PHP实现根据银行卡号判断银行
2015/04/29 PHP
屏蔽PHP默认设置中的Notice警告的方法
2016/05/20 PHP
PHP实现的登录页面信息提示功能示例
2017/07/24 PHP
php图片合成方法(多张图片合成一张)
2017/11/25 PHP
PHP程序员学习使用Swoole的理由
2018/06/24 PHP
CodeIgniter框架钩子机制实现方法【hooks类】
2018/08/21 PHP
tp5修改(实现即点即改)
2019/10/18 PHP
JavaScipt基本教程之前言
2008/01/16 Javascript
javascript 常用方法总结
2009/06/03 Javascript
简单实用的全选反选按钮例子
2013/10/18 Javascript
js实现点击按钮后给Div图层设置随机背景颜色的方法
2015/05/06 Javascript
AngularJS实践之使用NgModelController进行数据绑定
2016/10/08 Javascript
Extjs表单输入框异步校验的插件实现方法
2017/03/20 Javascript
浅谈angularjs依赖服务注入写法的注意点
2017/04/24 Javascript
微信小程序“摇一摇”的实例代码
2017/07/20 Javascript
vue-router2.0 组件之间传参及获取动态参数的方法
2017/11/10 Javascript
vue 出现data-v-xxx的原因及解决
2020/08/04 Javascript
NodeJS开发人员常见五个错误理解
2020/10/14 NodeJs
Python通过正则表达式选取callback的方法
2015/07/18 Python
基于Django框架利用Ajax实现点赞功能实例代码
2018/08/19 Python
Python 处理图片像素点的实例
2019/01/08 Python
Python日志无延迟实时写入的示例
2019/07/11 Python
python 中不同包 类 方法 之间的调用详解
2020/03/09 Python
Python基于codecs模块实现文件读写案例解析
2020/05/11 Python
HTML5地理定位实例
2014/10/15 HTML / CSS
Brookstone美国官网:独特新奇产品
2017/03/04 全球购物
Shopee马来西亚:随拍即卖,最佳行动电商拍卖平台
2017/06/05 全球购物
调解员先进事迹材料
2014/02/07 职场文书
企业党的群众路线教育实践活动学习心得体会
2014/10/31 职场文书
会计稽核岗位职责
2015/04/13 职场文书
导游词之舟山普陀山
2019/11/06 职场文书
Python 多线程之threading 模块的使用
2021/04/14 Python