Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法


Posted in Python onMay 26, 2020

1、背景

最近有个项目,需要搭建一个socket服务器,一个web服务器,然后实现两个服务器之间的通讯交互。刚开始的方案是用Python中socket模块实现一个多线程的socket服务器,然后用Flask实现一个web服务器,他们之前通过线程交互实现通讯。
但是在我看来这个方案有例外一个更好的解决方法,就是用Torndao框架。鉴于网上用Tornado实现一个程序同时实现web服务和socket服务器并且实现交互的文章几乎没有,所以记录一下。觉得写得好麻烦点个赞,写得不好请指出,有疑问可以留言。

2、准备

2.1、环境部署

  • Python3.x
  • pip3 install Tornado

2.2、目录结构

Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

目录结构如上图,这个目录结构包括文件命名只是我的个人习惯。其实目录结构不固定,只要合理就行。另外,原本项目是前后分离的只需要实现API接口,所以我这里就没有涉及到HTML的东西。

3、服务器的实现

3.1、Socket服务器实现

socket服务器部分实现主要靠 Tornado中的TCPServer类

3.1.1、 导入类

socket_server.py:

from tornado.iostream import IOStream  # 这句可以没有,只是作为参数的代码提示
from tornado.tcpserver import TCPServer

3.1.2、 构建一个Connecter类

socket_server.py:

class Connecter:

  clients = set()   # 存放连接的客户端

  async def init(self, stream: IOStream, address: tuple):
    """
    注意这个不是构造方法,这里不用构造方法是为了方便后续的与web端相互通信
    """
    self.stream, self.address = stream, address
    self.clients.add(self)
    print("{address} 上线!".format(address=address))
    self.stream.set_close_callback(self.onClose) # 客户端离线的时候会被调用
    await self.receive()    # 接受消息

  async def receive(self):
    """
    接受消息
    """
    while True:
      try:  # 因为异步的原因。可能设备离线后还在接收消息,所以try一下,不让错误打印出来,其实打印了错误也不影响程序运行
        data = await self.stream.read_bytes(num_bytes=1024, partial=True)  # num_bytes:每次最多接收字节,partial:数据中断后视为接收完成
        print(data)
        # TODO:接收到数据的处理
      except: 
        pass

  def send(self, data):
    """
    发送消息
    :param data: 消息内容
    """
    self.stream.write(bytes(data.encode('utf8')))

  def onClose(self):
    """
    客户端离线
    """
    print("{address} 离线!".format(address=self.address))
    self.clients.remove(self) # 在clients内删掉该客户端

3.1.3、 构建一个SocketServer类

socket_server.py:

class SocketServer(TCPServer):   # 需要继承TCPServer这个类
  async def handle_stream(self, stream: IOStream, address: tuple):  # 实现类里面的handle_stream方法
    await Connecter().init(stream, address)   # 每次有客户端连入都实例化一个Connecter类

3.2、Web服务器实现

3.2.1、 实现一个requestHandler

web_test.py:

from tornado.web import RequestHandler   # 导入RequestHandler类


class TestApiHandler(RequestHandler):    # 继承RequestHandler类

  def get(self):   # 实现GET方法,GET请求会执行这个方法
    pass

  def post(self):   # 实现POST方法,POST请求会执行这个方法
    pass

3.2.2、 实现web app

web_server.py:

from tornado.web import Application     # 导入Tornado的Application类
from .src.web_test import TestApiHandler  # 导入我们自己写的TestApiHandler类


def webServerApp():   # 构造出webApp
  return Application([
    (r'/api_test/', TestApiHandler),  # 把/api_test/路由到TestApiHandler
  ])

3.3、程序入口

3.3.1、 导入web_server和socket_server,还有导入tornado的ioloop

main.py:

from web_server.web_server import webServerApp
from socket_server.socket_server import SocketServer
from tornado import ioloop
from tornado.options import define, options

3.3.2、 定义默认端口

main.py

#这里用define定义端口,可以方便使用命令行参数的形式修改端口
define("socketPort", 8888, type=int)  # socket默认使用8888端口
define("webPort", 8080, type=int)    # web默认使用8080端口

3.3.3、 启动代码

main.py

def main():
  socket_server = SocketServer()
  socket_server.listen(options.socketPort, '0.0.0.0')
  print("socket服务器启动,端口:{port}".format(port=options.socketPort))
  app = webServerApp()
  app.listen(options.webPort, '0.0.0.0')
  print("web服务器启动,端口:{port}".format(port=options.webPort))
  ioloop.IOLoop.current().start()


if __name__ == '__main__':
  main()

4、服务器运行效果

到此,一个混合型的socket+web服务器已经搭建好了。我们我们运行main.py文件可以看到打印的信息,socket和web都正常运行。

Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

我在这里简单地写了一个socket客户端测试,代码如下:

import socket
import datetime


class Client:

  def __init__(self):
    with socket.create_connection(("127.0.0.1", 8888)) as sock:
      while True:
        msg = sock.recv(1024)
        if len(msg) > 0:
          print(msg)
          sock.send(bytes(str(datetime.datetime.now).encode('utf8')))
        msg = []
            
        

if __name__ == "__main__":
  Client()

Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

可以看到tornado异步的形式实现了多客户端同时接入socket。同时也可以测试web接口是正常的,如下图:

Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

5、Web服务器与Socket服务器交互

重点来了,web和socket怎样实现交互呢?其实很简单。

5.2、 web >> socket

web_test.py -> TestApiHandler -> post:

5.2.1、 导入Connecter类

from socket_server.socket_server import Connecter

5.2.2、 实现请求接口发送消息到socket客户端

def post(self):   # 实现POST方法,POST请求会执行这个方法
    msg = self.get_argument("msg") # 得到post请求中的msg的值
    ip = self.get_argument('ip')  # 得到要发送的ip
    c = Connecter()   # 实例化Connecter类
    counter = 0   # 记录发送到客户端的个数
    for client in c.clients:  # type:Connecter
      if client.address[0] == ip:   # 根据ip发送
        client.send(msg)  # 发送消息
        counter += 1    # 计数加1
    self.write("{'send_counter':" + str(counter) + "}")

5.2.3、 效果

请求接口可以返回数据,已经成功发送一个客户端

Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

客户端也能收到消息:

Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

5.1、 socket >> web

其实socket发送的消息让web马上收到消息是不太现实的,但是我们可以把数据保存起来(可以是数据库、全局变量、缓存……),然后通过api接口再把数据取出。另外还有一种方法是通过socket和websocket进行交互通讯,这种方法是推荐的方法,同样的也可以用Tornado去实现,感兴趣可以去研究一下也很简单。如何有需要我提供socket、websocket、web三个端都互相交互的例子可以留言。
这里为了简单一点,我使用一个类作为全局变量来保存数据,然后用接口访问,拿出这个类的值来演示一下效果。

5.1.1、 声明类作为全局变量

socket_data_processing.py

class SocketData:
  msg = ""

5.1.2、 接受到的消息保存到这个类里面的msg

socket_server.py -> Connecter -> receive

async def receive(self):
    """
    接受消息
    """
    while True:
      try:  # 因为异步的原因。可能设备离线后还在接收消息,所以try一下,不让错误打印出来,其实打印了错误也不影响程序运行
        data = await self.stream.read_bytes(num_bytes=1024, partial=True)  # num_bytes:每次最多接收字节,partial:数据中断后视为接收完成
        print(data)
        from .src.socket_data_processing import SocketData
        SocketData.msg = data.decode('utf8')
      except:
        pass

5.1.3、 用get方法显示socket显示回来的数据

web_test.py -> TestApiHandler -> get:

def get(self):   # 实现GET方法,GET请求会执行这个方法
    from socket_server.src.socket_data_processing import SocketData
    self.write(SocketData.msg)

5.1.4、 效果

Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

可以看到,从socket传过来的字符串,被我通过Api读取到了。

6、完整代码GitHub:https://github.com/JohnDoe1996/socket-web

到此这篇关于Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法的文章就介绍到这了,更多相关Python  WEB服务器Socket服务器共存交互内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
使用Python的Django框架实现事务交易管理的教程
Apr 20 Python
在Python的while循环中使用else以及循环嵌套的用法
Oct 14 Python
Windows下python2.7.8安装图文教程
May 26 Python
python爬虫框架talonspider简单介绍
Jun 09 Python
Python 自动刷博客浏览量实例代码
Jun 14 Python
Python2和Python3的共存和切换使用
Apr 12 Python
Python直接赋值、浅拷贝与深度拷贝实例分析
Jun 18 Python
在django模板中实现超链接配置
Aug 21 Python
解决在pycharm运行代码,调用CMD窗口的命令运行显示乱码问题
Aug 23 Python
pytorch 彩色图像转灰度图像实例
Jan 13 Python
python3+opencv生成不规则黑白mask实例
Feb 19 Python
Python中glob库实现文件名的匹配
Jun 18 Python
tensorflow实现从.ckpt文件中读取任意变量
May 26 #Python
打印tensorflow恢复模型中所有变量与操作节点方式
May 26 #Python
tensorflow模型的save与restore,及checkpoint中读取变量方式
May 26 #Python
tensorflow从ckpt和从.pb文件读取变量的值方式
May 26 #Python
Pytorch转keras的有效方法,以FlowNet为例讲解
May 26 #Python
Django+Celery实现动态配置定时任务的方法示例
May 26 #Python
python删除某个目录文件夹的方法
May 26 #Python
You might like
一个可以找出源代码中所有中文的工具
2006/10/25 PHP
php 用sock技术发送邮件的函数
2007/07/21 PHP
PHP 数字左侧自动补0
2008/03/31 PHP
php通过sort()函数给数组排序的方法
2015/03/18 PHP
PHP ajax 异步执行不等待执行结果的处理方法
2015/05/27 PHP
php5对象复制、clone、浅复制与深复制实例详解
2019/08/14 PHP
激活 ActiveX 控件
2006/10/09 Javascript
js 变量类型转换常用函数与代码[比较全]
2009/12/01 Javascript
js 异步处理进度条
2010/04/01 Javascript
如何获取JQUERY AJAX返回的JSON结果集实现代码
2012/12/10 Javascript
jQuery替换字符串(实例代码)
2013/11/13 Javascript
nodejs批量修改文件编码格式
2015/01/22 NodeJs
JS+CSS实现模仿浏览器网页字符查找功能的方法
2015/02/26 Javascript
js随机生成字母数字组合的字符串 随机动画数字
2015/09/02 Javascript
JS+CSS实现电子商务网站导航模板效果代码
2015/09/10 Javascript
JavaScript学习笔记之取数组中最大值和最小值
2016/03/23 Javascript
基于javascript实现全屏漂浮广告
2016/03/31 Javascript
Ionic 2 实现列表滑动删除按钮的方法
2017/01/22 Javascript
Vue2单一事件管理组件通信
2017/05/09 Javascript
JavaScript实现动态添加Form表单元素的方法示例
2017/08/14 Javascript
浅谈webpack打包过程中因为图片的路径导致的问题
2018/02/21 Javascript
jQuery高级编程之js对象、json与ajax用法实例分析
2019/11/01 jQuery
python with statement 进行文件操作指南
2014/08/22 Python
修改默认的pip版本为对应python2.7的方法
2018/11/06 Python
一篇文章弄懂Python中所有数组数据类型
2019/06/23 Python
详解Java中一维、二维数组在内存中的结构
2021/02/11 Python
HTML5触摸事件(touchstart、touchmove和touchend)的实现
2020/05/08 HTML / CSS
关于毕业的中学校园广播稿
2014/01/26 职场文书
给老师的检讨书
2014/02/11 职场文书
预备党员入党自我评价范文
2014/03/10 职场文书
遵纪守法演讲稿
2014/05/23 职场文书
合作协议书范文
2014/08/20 职场文书
社区元宵节活动总结
2015/02/06 职场文书
稽核岗位职责
2015/02/10 职场文书
小学2016年第十八届推普周活动总结
2016/04/05 职场文书
golang特有程序结构入门教程
2021/06/02 Python