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 时间处理datetime实例
Sep 06 Python
python使用正则表达式检测密码强度源码分享
Jun 11 Python
Python 26进制计算实现方法
May 28 Python
详解python中的json和字典dict
Jun 22 Python
Python中pip更新和三方插件安装说明
Jul 08 Python
Python/ArcPy遍历指定目录中的MDB文件方法
Oct 27 Python
python 遍历列表提取下标和值的实例
Dec 25 Python
python rsync服务器之间文件夹同步脚本
Aug 29 Python
python实现二分类的卡方分箱示例
Nov 22 Python
使用pyhon绘图比较两个手机屏幕大小(实例代码)
Jan 03 Python
Django正则URL匹配实现流程解析
Nov 13 Python
Python+Matplotlib+LaTeX玩转数学公式
Feb 24 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
怎么样可以把 phpinfo()屏蔽掉?
2006/11/24 PHP
PHP上传文件时文件过大$_FILES为空的解决方法
2013/11/26 PHP
php使用unset()删除数组中某个单元(键)的方法
2015/02/17 PHP
PHP编程入门的基本语法知识点总结
2016/01/26 PHP
静态的动态续篇之来点XML
2006/12/23 Javascript
jQuery 方法大全方便学习参考
2010/02/25 Javascript
跨域请求之jQuery的ajax jsonp的使用解惑
2011/10/09 Javascript
jQuery当鼠标悬停时放大图片的效果实例
2013/07/03 Javascript
JS实现图片翻书效果示例代码
2013/09/09 Javascript
常见浏览器多长时间会提示“脚本运行时间过长”总结
2014/04/29 Javascript
js自动生成的元素与页面原有元素发生堆叠的解决方法
2014/09/04 Javascript
在Ubuntu系统上安装Ghost博客平台的教程
2015/06/17 Javascript
CascadeView级联组件实现思路详解(分离思想和单链表)
2016/04/12 Javascript
瀑布流的实现方式(原生js+jquery+css3)
2020/06/28 Javascript
jquery.Callbacks的实现详解
2016/11/30 Javascript
使用 NodeJS+Express 开发服务端的简单介绍
2017/04/07 NodeJs
详解js几个绕不开的事件兼容写法
2017/08/30 Javascript
VUE重点问题总结
2018/03/19 Javascript
chosen实现省市区三级联动
2018/08/16 Javascript
关于Vue Router中路由守卫的应用及在全局导航守卫中检查元字段的方法
2018/12/09 Javascript
keep-alive不能缓存多层级路由菜单问题解决
2020/03/10 Javascript
[54:10]完美世界DOTA2联赛PWL S2 Magma vs FTD 第二场 11.29
2020/12/03 DOTA
tensorflow中next_batch的具体使用
2018/02/02 Python
python3+PyQt5实现自定义分数滑块部件
2018/04/24 Python
python读取word文档,插入mysql数据库的示例代码
2018/11/07 Python
python实现飞机大战小游戏
2019/11/08 Python
html5 canvas实现圆形时钟代码分享
2013/12/25 HTML / CSS
应用化学专业本科生求职信
2013/09/29 职场文书
小学毕业感言300字
2014/02/19 职场文书
交通事故私了协议书
2014/04/16 职场文书
教师国庆节演讲稿范文2014
2014/09/21 职场文书
考研英语复习计划
2015/01/19 职场文书
伏羲庙导游词
2015/02/09 职场文书
2015年妇女工作总结
2015/05/14 职场文书
python for循环赋值问题
2021/06/03 Python
MySQL多表查询机制
2022/03/17 MySQL