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中字典(dict)和列表(list)的排序方法实例
Jun 16 Python
在Python的web框架中中编写日志列表的教程
Apr 30 Python
TensorFlow实现Logistic回归
Sep 07 Python
Python matplotlib通过plt.scatter画空心圆标记出特定的点方法
Dec 13 Python
Flask框架模板继承实现方法分析
Jul 31 Python
用python生成与调用cntk模型代码演示方法
Aug 26 Python
python 读取更新中的log 或其它文本方式
Dec 24 Python
对tensorflow中tf.nn.conv1d和layers.conv1d的区别详解
Feb 11 Python
django使用JWT保存用户登录信息
Apr 22 Python
python代码区分大小写吗
Jun 17 Python
如何Tkinter模块编写Python图形界面
Oct 14 Python
Python提取视频中图片的示例(按帧、按秒)
Oct 22 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的网址
2006/11/25 PHP
php获取文件大小的方法
2014/02/26 PHP
PHP生成静态HTML文档实现代码
2016/06/23 PHP
Laravel框架控制器的request与response用法示例
2019/09/30 PHP
又一个图片自动缩小的JS代码
2007/03/10 Javascript
jquery下checked取值问题的解决方法
2012/08/09 Javascript
分享8款优秀的 jQuery 加载动画和进度条插件
2012/10/24 Javascript
Javascript实现返回上一页面并刷新的小例子
2013/12/11 Javascript
JS实现模仿微博发布效果实例代码
2013/12/16 Javascript
第四篇Bootstrap网格系统偏移列和嵌套列
2016/06/21 Javascript
基于JavaScript实现鼠标向下滑动加载div的代码
2016/08/31 Javascript
纯JS打造网页中checkbox和radio的美化效果
2016/10/13 Javascript
实现一个简单的vue无限加载指令方法
2017/01/10 Javascript
浅谈nodejs中的类定义和继承的套路
2017/07/26 NodeJs
浅谈vue自定义全局组件并通过全局方法 Vue.use() 使用该组件
2017/12/07 Javascript
Nodejs模块载入运行原理
2018/02/23 NodeJs
[01:24:34]2014 DOTA2华西杯精英邀请赛5 24 DK VS LGD
2014/05/25 DOTA
[01:46]DOTA2上海特锦赛小组赛英文解说KotlGuy采访
2016/02/27 DOTA
使用优化器来提升Python程序的执行效率的教程
2015/04/02 Python
python实现的config文件读写功能示例
2019/09/24 Python
python实现小世界网络生成
2019/11/21 Python
Python+OpenCV实现旋转文本校正方式
2020/01/09 Python
python中pandas库中DataFrame对行和列的操作使用方法示例
2020/06/14 Python
基于TensorFlow的CNN实现Mnist手写数字识别
2020/06/17 Python
解决CSS3 transition-delay 属性默认值0不带单位失效的问题
2020/10/29 HTML / CSS
MANGO官方网站:西班牙芒果服装品牌
2017/01/15 全球购物
BRASTY捷克:购买香水、化妆品、手袋和手表
2017/07/12 全球购物
本科生详细的自我评价
2013/09/19 职场文书
艺术设计专业求职自荐信
2014/05/19 职场文书
领导干部保密承诺书
2014/08/30 职场文书
纪念九一八事变演讲稿1000字
2014/09/14 职场文书
2014年村支部书记四风对照检查材料思想汇报
2014/10/02 职场文书
医院营销工作计划
2015/01/16 职场文书
伊索寓言读书笔记
2015/06/30 职场文书
导游词之无锡梅园
2019/11/28 职场文书
对Keras自带Loss Function的深入研究
2021/05/25 Python