python使用MQTT给硬件传输图片的实现方法

最近因需要用python写一个微服务来用MQTT给硬件传输图片,其中python用的是flask框架,大概流程如下:

协议为:

需要将图片数据封装成多个消息进行传输,每个消息传输的数据字节数为1400Byte。
消息(MQTT Payload) 格式:Web服务器-------->BASE:

反馈:BASE---------> Web服务器:

如果Web服务器发送完一个“数据传输消息”后,5S内没有收到MQTT“反馈消息”或者收到的反馈中显示“数据包不完整”,则重发该“数据传输消息”。

程序流程图

根据上面的协议,可以得到如下的流程图:

代码如下:

# encoding:utf-8
from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse
from PIL import Image
from io import BytesIO
import requests
import os, logging, time
import paho.mqtt.client as mqtt
import struct
from flask_cors import *
# 日志配置信息
logging.basicConfig(
  level=logging.INFO,
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s (runing by %(funcName)s',
)
class Mqtt(object):
  def __init__(self, img_data, size):
    self.MQTTHOST = '*******'
    self.MQTTPORT = "******"
    # 订阅和发送的主题
    self.topic_from_base = 'mqttTestSub'
    self.topic_to_base = 'mqttTestPub'
    self.client_id = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
    self.client = mqtt.Client(self.client_id)
    # 完成链接后的回掉函数
    self.client.on_connect = self.on_connect
    # 图片大小
    self.size = size
    # 用于跳出死循环,结束任务
    self.finished = None
    # 包的编号
    self.index = 0
    # 将收到的图片数据按大小分成列表
    self.image_data_list = [img_data[x:x + 1400] for x in range(0, self.size, 1400)]
    # 记录发布后的数据,用于监控时延
    self.pub_time = 0
    self.header_to_base = 0xffffeeee
    self.header_from_base = 0xeeeeffff
    # 功能标识
    self.function_begin = 0x01
    self.function_doing = 0x02
    self.function_finished = 0x03
    # 包的完整和非完整状态
    self.whole_package = 0x01
    self.bad_package = 0x00
    # 头信息的格式,小端模式
    self.format_to_base = "<Lbhh"
    self.format_from_base = "<Lbhb"
    # 如果重发包时,用于检查是否重发第一个包
    self.first = True
    # 如果重发包时,用于检查是否重发最后一个包
    self.last = False
    self.begin_data = 'image.jpg;' + str(self.size)
  # 链接mqtt服务器函数
  def on_mqtt_connect(self):
    self.client.connect(self.MQTTHOST, self.MQTTPORT, 60)
    self.client.loop_start()
  # 链接完成后的回调函数
  def on_connect(self, client, userdata, flags, rc):
    logging.info("+++ Connected with result code {} +++".format(str(rc)))
    self.client.subscribe(self.topic_from_base)
  # 订阅函数
  def subscribe(self):
    self.client.subscribe(self.topic_from_base, 1)
    # 消息到来处理函数
    self.client.on_message = self.on_message
  # 接收到信息后的回调函数
  def on_message(self, client, userdata, msg):
    # 如果接受第一个包则不需要重发第一个
    self.first = False
    # 将接受到的包进行解压,得到一个元组
    base_tuple = struct.unpack(self.format_from_base, msg.payload)
    logging.info("+++ imageData's letgth is {}, base_tupe is {} +++".format(self.size, base_tuple))
    logging.info("+++ package_number is {}, package_status_from_base is {} +++"
           .format(base_tuple[2], base_tuple[3]))
    # 检查接受到信息的头部是否正确
    if base_tuple[0] == self.header_from_base:
      logging.info("+++ function_from_base is {} +++".format(base_tuple[1]))
      # 是否完成传输,如果完成则退出
      if base_tuple[1] == self.function_finished:
        logging.info("+++ finish work +++")
        self.finished = 1
        self.client.disconnect()
      else:
        # 是否是最后一个包
        if self.index == len(self.image_data_list) - 1:
          self.publish('finished', self.function_finished)
          self.last = True
          logging.info("+++ finished_data_to_base is finished+++")
        else:
          # 如果接收到的包不是 0x03则进行传送数据
          if base_tuple[1] == self.function_begin or base_tuple[1] == self.function_doing:
            logging.info("+++ package_number is {}, package_status_from_base is {} +++"
                   .format(base_tuple[2],base_tuple[3]))
            # 如果数据的反馈中,包的状态是1则继续发下一个包
            if base_tuple[3] == self.whole_package:
              self.publish(self.index, self.function_doing)
              logging.info("+++ data_to_base is finished+++")
              self.index += 1
            # 如果数据的反馈中,包的状态是0则重发数据包
            elif base_tuple[3] == self.bad_package:
              re_package_number = base_tuple[2]
              self.publish(re_package_number-1, self.function_doing)
              logging.info("+++ re_data_to_base is finished+++")
            else:
              logging.info("+++ package_status_from_base is not 0 or 1 +++")
              self.client.disconnect()
          else:
            logging.info("+++ function_identifier is illegal +++")
            self.client.disconnect()
    else:
      logging.info("+++ header_from_base is illegal +++")
      self.client.disconnect()
  # 数据发送函数
  def publish(self, index, fuc):
    # 看是否是最后一个包
    if index == 'finished':
      length = 0
      package_number = 0
      data = b''
    else:
      length = len(self.image_data_list[index])
      package_number = index
      data = self.image_data_list[index]
    # 打包数据头信息
    buffer = struct.pack(
      self.format_to_base,
      self.header_to_base,
      fuc,
      package_number,
      length
    )
    to_base_data = buffer + data
    # mqtt发送
    self.client.publish(
      self.topic_to_base,
      to_base_data
    )
    self.pub_time = time.time()
  # 发送第一个包函数
  def publish_begin(self):
    buffer = struct.pack(
      self.format_to_base,
      self.header_to_base,
      self.function_begin,
      0,
      len(self.begin_data.encode('utf-8')),
    )
    begin_data = buffer + self.begin_data.encode('utf-8')
    self.client.publish(self.topic_to_base, begin_data)
  # 控制函数
  def control(self):
    self.on_mqtt_connect()
    self.publish_begin()
    begin_time = time.time()
    self.pub_time = time.time()
    self.subscribe()
    while True:
      time.sleep(1)
      # 超过5秒重传
      date = time.time() - self.pub_time
      if date > 5:
        # 是否重传第一个包
        if self.first == True:
          self.publish_begin()
          logging.info('+++ this is timeout first_data +++')
        # 是否重传最后一个包
        elif self.last == True:
          self.publish('finished', self.function_finished)
          logging.info('+++ this is timeout last_data +++')
        else:
          self.publish(self.index-1, self.function_doing)
          logging.info('+++ this is timeout middle_data +++')
      if self.finished == 1:
        logging.info('+++ all works is finished+++')
        break
    print(str(time.time()-begin_time) + 'begin_time - end_time')
app = Flask(__name__)
api = Api(app)
CORS(app, supports_credentials=True)
# 接受参数
parser = reqparse.RequestParser()
parser.add_argument('url', help='mqttImage url', location='args', type=str)
class GetImage(Resource):
  # 得到参数并从图床下载到本地
  def get(self):
    args = parser.parse_args()
    url = args.get('url')
    response = requests.get(url)
    # 获取图片
    image = Image.open(BytesIO(response.content))
    # 存取图片
    add = os.path.join(os.path.abspath(''), 'image.jpg')
    image.save(add)
    # 得到图片大小
    size = os.path.getsize(add)
    f = open(add, 'rb')
    imageData = f.read()
    f.close()
    # 进行mqtt传输
    mqtt = Mqtt(imageData, size)
    mqtt.control()
    # 删除文件
    os.remove(add)
    logging.info('*** the result of control is {} ***'.format(1))
    return jsonify({
      "imageData": 1
    })
api.add_resource(GetImage, '/image')
if __name__ == '__main__':
  app.run(debug=True, host='0.0.0.0')

总结

以上所述是小编给大家介绍的python使用MQTT给硬件传输图片的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • videocapture库制作python视频高速传输程序

    1,首先是视频数据[摄像头图像]的采集,通常可以使用vfw在vc或者vb下实现,这个库我用的不好,所以一直不怎么会用.现在我们用到的是python的videocapture库,这个库用起来很简单,如下: 复制代码 代码如下: from VideoCapture import Devicecam = Device()cam.setResolution(320,240)   #设置显示分辨率cam.saveSnapshot('demo.jpg') #抓取并保存图片 这样,你就得到了一张图片.当然,要

  • python使用tcp实现局域网内文件传输

    本文为大家分享了python使用tcp实现局域网内文件传输的具体代码,供大家参考,具体内容如下 功能: 可以利用python创建的TCP客户端从我们自己搭建的TCP服务器上下载文件. 实现需求: 安装socket模块 简单了解sokcet模块用法 服务器代码如下: import socket def file_deal(file_name): # 定义函数用于处理用户索要下载的文件 try: # 二进制方式读取 files = open(file_name, "rb") mes = f

  • python:socket传输大文件示例

    文件可以传输,但是对比传输前后的文件:socket_test.txt,末尾有一些不一致服务端代码: #!/usr/bin/python # -*- coding: utf-8 -*- import sys reload(sys) sys.setdefaultencoding("utf-8") import time ''' 等待连接 等待发送文件 读取数据 写入文件并且保存 等待连接 ''' import socket import threading import time impo

  • python实现的一个p2p文件传输实例

    考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者scp之类的文件传输方式只能做到一个点往下分发这个文件,这个时候下发的速度就会比较的慢,基于以上原因,我写了一个基于bt协议传输文件的小工具,实际测试,传输到10个机房,70多台机器传输一个240M的这个内核文件,到所有的机器,源采用限速2m/s的上传速度,测试的结

  • Python实现Windows和Linux之间互相传输文件(文件夹)的方法

    项目中需要从Windows系统传输ISO文件到Linux测试系统,然后再Linux测试系统里安装这个ISO文件.所以就需要实现如何把文件从Windows系统传输到Linux系统中. 在项目中使用了pscp.exe这个工具,只要按照pscp.exe的使用说明操作即可.只要进入pscp.exe的安装位置,然后输入pscp即可查看pscp的使用说明. 下面是我机器上的: 使用Python实现也挺简单的,下面的code主要介绍4中情况: 1. windows传输文件到Linux 2. windows传输

  • python实现类似ftp传输文件的网络程序示例

    此代码在linux上编写,适用于linux,windows下需要更改几个命令.1.客户端输入IP,端口,可服务器端进行连接,被要求输入用户名和密码进行验证.2.使用独立的模块来验证登录用户(技术有限,不支持客户端创建用户),用户名:ftpuser  密码:userlogin2.客户端登录验证成功后,可使用?或者help查看可使用的命令. ftpserver.py 复制代码 代码如下: #!/usr/bin/env python#-*- coding:utf-8 "Program for ftp

  • python实现获取客户机上指定文件并传输到服务器的方法

    本文实例讲述了python实现获取客户机上指定文件并传输到服务器的方法.分享给大家供大家参考.具体分析如下: 该程序实现了,把目标机器的某个目录(可控)的所有的某种类型文件(可控)全部获取并传到己方的机器上. 1.用了base64的encode(infile,outfile)加密,以及decode(infile,outfile)解密,这是2进制加密解密 2.用zip压缩 3.socket中server.py放到自己这方python server.py,然后client.py放到目标机器,然后py

  • Python Socket传输文件示例

    发送端可以不停的发送新文件,接收端可以不停的接收新文件. 例如:发送端输入:e:\visio.rar,接收端会默认保存为 e:\new_visio.rar,支持多并发,具体实现如下: 接收端: 方法一: #-*- coding: UTF-8 -*- import socket,time,SocketServer,struct,os,thread host='192.168.50.74' port=12307 s=socket.socket(socket.AF_INET,socket.SOCK_S

  • Python实现基于HTTP文件传输实例

    本文实例讲述了Python实现基于HTTP文件传输的方法.分享给大家供大家参考.具体实现方法如下: 一.问题: 因为需要最近看了一下通过POST请求传输文件的内容 并且自己写了Server和Client实现了一个简单的机遇HTTP的文件传输工具 二.实现代码: Server端: 复制代码 代码如下: #coding=utf-8 from BaseHTTPServer import BaseHTTPRequestHandler import cgi class   PostHandler(Base

  • Python实现的简单文件传输服务器和客户端

    还是那个题目(题目和流程见java版本),感觉光用java写一点新意也没有,恰巧刚学习了python,何不拿来一用,呵呵: 服务器端: import SocketServer, time class MyServer(SocketServer.BaseRequestHandler): userInfo = { 'yangsq' : 'yangsq', 'hudeyong' : 'hudeyong', 'mudan' : 'mudan' } def handle(self): print 'Con

  • Python爬虫抓取手机APP的传输数据

    大多数APP里面返回的是json格式数据,或者一堆加密过的数据 .这里以超级课程表APP为例,抓取超级课程表里用户发的话题. 1.抓取APP数据包 方法详细可以参考这篇博文:Fiddler如何抓取手机APP数据包 得到超级课程表登录的地址:http://120.55.151.61/V2/StudentSkip/loginCheckV4.action 表单: 表单中包括了用户名和密码,当然都是加密过了的,还有一个设备信息,直接post过去就是. 另外必须加header,一开始我没有加header得

  • 使用Python的Flask框架实现视频的流媒体传输

    Flask 是一个 Python 实现的 Web 开发微框架.这篇文章是一个讲述如何用它实现传送视频数据流的详细教程. 我敢肯定,现在你已经知道我在O'Reilly Media上发布了有关Flask的一本书和一些视频资料.在这些上面,Flask框架介绍的覆盖面是相当完整的,出于某种原因,也有一小部分的功能没有太多的提到,因此我认为在这里写一篇介绍它们的文章是一个好主意. 这篇文章是专门介绍流媒体的,这个有趣的功能让Flask应用拥有这样一种能力,以分割成小数据块的方式,高效地为大型请求提供数据,

  • python实现udp数据报传输的方法

    本文实例讲述了Python实现UDP数据报传输的方法,非常具有实用价值.分享给大家供大家参考.具体方法分析如下: 服务端代码: import socket port = 8081 s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #从给定的端口,从任何发送者,接收UDP数据报 s.bind(("",port)) print 'waiting on port:',port while True: data,addr = s.recvf

随机推荐