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学习之hook钩子的原理和使用
Oct 25 Python
pygame游戏之旅 添加icon和bgm音效的方法
Nov 21 Python
PyQt5下拉式复选框QComboCheckBox的实例
Jun 25 Python
Python实现计算对象的内存大小示例
Jul 10 Python
Python定时任务工具之APScheduler使用方式
Jul 24 Python
解决Pytorch 训练与测试时爆显存(out of memory)的问题
Aug 20 Python
关于numpy中eye和identity的区别详解
Nov 29 Python
Python简单实现区域生长方式
Jan 16 Python
基于Python fminunc 的替代方法
Feb 29 Python
python使用re模块爬取豆瓣Top250电影
Oct 20 Python
Python实现简单的2048小游戏
Mar 01 Python
Python字符串常规操作小结
Apr 03 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
PHP中防止SQL注入攻击和XSS攻击的两个简单方法
2010/04/15 PHP
PHP最常用的ini函数分析 针对PHP.ini配置文件
2010/04/22 PHP
PHP实现链式操作的原理详解
2016/09/16 PHP
event.srcElement+表格应用
2006/08/29 Javascript
用JavaScrpt实现文件夹简单轻松加密的实现方法图文
2008/09/08 Javascript
jQuery输入城市查看地图使用介绍
2013/05/08 Javascript
让alert不出现弹窗的两种方法
2014/05/18 Javascript
Javascript实现简单的富文本编辑器附演示
2014/06/16 Javascript
Nodejs实现的一个简单udp广播服务器、客户端
2014/09/25 NodeJs
基于JQuery制作可编辑的表格特效
2014/12/23 Javascript
Node.js事件循环(Event Loop)和线程池详解
2015/01/28 Javascript
bootstrap手风琴制作方法详解
2017/01/11 Javascript
Bootstrap表单使用方法详解
2017/02/17 Javascript
js使用highlight.js高亮你的代码
2017/08/18 Javascript
Vue实现购物车场景下的应用
2017/11/27 Javascript
jquery实现的简单轮播图功能【适合新手】
2018/08/17 jQuery
浅析JS中什么是自定义react数据验证组件
2018/10/19 Javascript
基于vue-cli3创建libs库的实现方法
2019/12/04 Javascript
Vue3新特性之在Composition API中使用CSS Modules
2020/07/13 Javascript
在Python的Django框架中生成CSV文件的方法
2015/07/22 Python
Python Web编程之WSGI协议简介
2018/07/18 Python
tensorflow 用矩阵运算替换for循环 用tf.tile而不写for的方法
2018/07/27 Python
python leetcode 字符串相乘实例详解
2018/09/03 Python
以SQLite和PySqlite为例来学习Python DB API
2020/02/05 Python
python filecmp.dircmp实现递归比对两个目录的方法
2020/05/22 Python
CSS3动画和HTML5新特性详解
2020/08/31 HTML / CSS
canvas绘图按照contain或者cover方式适配并居中显示
2019/02/18 HTML / CSS
美国一家著名的手表在线折扣网站:Discount Watch Store
2020/02/24 全球购物
非功能性需求都包括哪些方面
2013/10/29 面试题
3D空间设计学生找工作的自我评价
2013/10/28 职场文书
消防器材管理制度
2014/01/28 职场文书
期末自我鉴定
2014/02/02 职场文书
学风建设演讲稿
2014/09/12 职场文书
股东出资证明书(正规版)
2014/09/24 职场文书
本科毕业论文致谢怎么写
2015/05/14 职场文书
法人身份证明书
2015/06/18 职场文书