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 ljust rjust center输出
Sep 06 Python
linux环境下安装pyramid和新建项目的步骤
Nov 27 Python
安装ElasticSearch搜索工具并配置Python驱动的方法
Dec 22 Python
Pandas 数据框增、删、改、查、去重、抽样基本操作方法
Apr 12 Python
Python开启线程,在函数中开线程的实例
Feb 22 Python
Python3中列表list合并的四种方法
Apr 19 Python
mac系统下Redis安装和使用步骤详解
Jul 09 Python
Django admin.py 在修改/添加表单界面显示额外字段的方法
Aug 22 Python
利用Python制作动态排名图的实现代码
Apr 09 Python
什么是python的列表推导式
May 26 Python
Win10下用Anaconda安装TensorFlow(图文教程)
Jun 18 Python
python中HTMLParser模块知识点总结
Jan 25 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
Terran魔法科技
2020/03/14 星际争霸
PHP出错界面
2006/10/09 PHP
php 在线打包_支持子目录
2008/06/28 PHP
php上传文件并存储到mysql数据库的方法
2015/03/16 PHP
PHP魔术方法以及关于独立实例与相连实例的全面讲解
2016/10/18 PHP
基于PHP实现生成随机水印图片
2020/12/09 PHP
URI、URL和URN之间的区别与联系
2006/12/20 Javascript
jQuery温习篇 强大的JQuery选择器
2010/04/24 Javascript
Javascript全局变量var与不var的区别深入解析
2013/12/09 Javascript
js下将阿拉伯数字每三位一逗号分隔(如:15000000转化为15,000,000)
2014/06/02 Javascript
一个获取第n个元素节点的js函数
2014/09/02 Javascript
javascript 面向对象封装与继承
2014/11/27 Javascript
理解js对象继承的N种模式
2016/01/25 Javascript
[原创]Javascript 实现广告后加载 可加载百度谷歌联盟广告
2016/05/11 Javascript
基于JS实现发送短信验证码后的倒计时功能(无视页面刷新,页面关闭不进行倒计时功能)
2016/09/02 Javascript
详解微信小程序开发之——wx.showToast(OBJECT)的使用
2017/01/18 Javascript
ES6解构赋值实例详解
2017/10/31 Javascript
vue实现简易计算器功能
2021/01/20 Vue.js
Python 3.x 连接数据库示例(pymysql 方式)
2017/01/19 Python
python实现泊松图像融合
2018/07/26 Python
pyqt5对用qt designer设计的窗体实现弹出子窗口的示例
2019/06/19 Python
使用python对多个txt文件中的数据进行筛选的方法
2019/07/10 Python
Django框架中序列化和反序列化的例子
2019/08/06 Python
Windows下实现将Pascal VOC转化为TFRecords
2020/02/17 Python
python 使用递归回溯完美解决八皇后的问题
2020/02/26 Python
Python实现扫码工具的示例代码
2020/10/09 Python
HTML5制作表格样式
2016/11/15 HTML / CSS
HTML5如何使用SVG的方法示例
2019/01/11 HTML / CSS
魅力惠奢品线上平台:MEI.COM
2016/11/29 全球购物
Agoda香港:全球特价酒店预订
2017/05/07 全球购物
Made in Design德国:设计师家具、灯具和装饰
2019/10/31 全球购物
个人自我鉴定写法
2013/11/30 职场文书
蜜蜂引路教学反思
2014/02/04 职场文书
教师病假条范文
2015/08/17 职场文书
少年的你:世界上没有如果,要在第一次就勇敢的反抗
2019/11/20 职场文书
Nginx优化服务之网页压缩的实现方法
2021/03/31 Servers