xuehu96 发表于 2019-7-13 10:37

【python】OTA升级服务端程序,TCP连接,带文档

本帖最后由 xuehu96 于 2019-7-13 20:05 编辑

# OTA_Python_Server 指令
>使用TCP与服务器建立链接,端口可自定义
固件为bin文件,每次发送1024字节,速率和发送方式可控


## 升级流程
1. 发送设备名字和本地版本
2. 发送传输方式
3. 发送控制指令

### 自动传输指令发送实例
```
device#test12
auto
start#10kB/s
```
### 控制传输指令发送实例
```
device#test12
control
next
next
...(直到传完)
next
```


## 1.发送设备名字和本地版本
#### 发送数据:device#[设备名][本地版本号]
示例数据:
```
device#test12
```
- device为关键字,不可修改,全部小写
- #test为设备名,只能为小写字母(不能有空格和数字)
- #12为版本号,全部为数字

固件命名为`test13.bin`固件版本号大于设备版本号才会升级
>新版本大于旧版本50个版本号则无法匹配到新固件
test13.bintest15.bin同时存在 则会升级为test15.bin

正确返回:
+ newver:15 服务器有新版本v15(进入第二步)
- noupdates 没有新版本(没有新版本,服务器主动断开)

错误代码:
- cmderr:1 未匹配到指令
- cmderr:2 指令发送顺序错误
- cmderr:3 设备名不存在或版本号无法匹配


## 2.发送传送方式指令和接收固件
> 固件的传送分为两种方式1.自动传输(auto) 2.控制传输(control)

### 2.1自动传输
#### 2.1.1发送`auto`
发送数据:
- `auto`
- auto为小写

正确返回:
- 固件的大小
- 例如`16772`
- 单位为字节,字符串,10进制,16772为16772字节

错误返回:
- cmderr:1 未匹配到指令
- cmderr:2 指令发送顺序错误

#### 2.1.2发送`start#[传输速率]kB/s`
发送数据例子
```
start#10kB
start#50kB/s
```
注意:
- start为关键字 小写
- #10kB为传输速率 范围为1-99kB
- #必须写k小写B大写
- `/s`可以省略

正确返回:
- 16进制固件数据

错误返回:
- cmderr:1 未匹配到指令
- cmderr:2 指令发送顺序错误

#### 2.1.3发送完毕
发送结束,服务器主动断开连接

### 2.2控制传输
#### 2.2.1发送`control`
发送数据:
- `control`
- control为小写

正确返回:
- 固件的大小 例如`16772`

错误返回:
- cmderr:1 未匹配到指令
- cmderr:2 指令发送顺序错误

#### 2.2.2下一个数据包`next`
- 请求往后1024个字节的固件数据,如果传输结束,服务器会断开连接

#### 2.2.3重发数据包`resend`
- 如果当前收到的数据有问题,可以重新请求发送当前数据包

#### 2.2.4主动结束传输`exit`
- 发送exit退出传输
- 服务器最后一个数据包发完会发送endoffile并主动断开客户端

python代码,使用python3socketserver模块

import socketserver
import time
import os
import re

class MyTcpHandler(socketserver.BaseRequestHandler):
    def handle(self):
      step=0
      filepath = 'null'
      filesize = 0
      files = None
      conbuf = None
      limit = None
      cnt = 0
      while True:
            try:
                data = self.request.recv(1024)
                print(data)
                if not data: break# 此行代码针对linux系统

                recvstr = data.decode(encoding="utf-8")
                if step == 0:#判断设备名
                  if recvstr.find('device')==-1:
                        self.request.send(b"cmderr:1")#未匹配到指令
                  else:
                        modestr = recvstr
                        oldver =re.sub(r'\D', "", modestr)
                        filename =re.sub(r'\d', "", modestr)
                        print ('ver'+oldver+'name='+filename)
                        print()
                        for i in range(50):
                            if os.path.exists(os.path.abspath('.')+'\\bin\\'+filename+str(int(oldver)+i+1)+'.bin')==True:
                              filepath = os.path.abspath('.')+'\\bin\\'+filename+str(int(oldver)+i+1)+'.bin'
                              print(os.path.abspath('.')+'\\bin\\'+filename+str(int(oldver)+i+1)+'.bin')
                              

                        if filepath == 'null':
                            self.request.send(b"cmderr:3")#未匹配到指令
                        else:
                            step=1
                            newver = "newver:"+re.sub(r'\D', "", filepath)
                            self.request.send(newver.encode(encoding="utf-8"))

                            #打开文件
                            filesize = os.path.getsize(filepath)
                            files = open(filepath,'rb')
                           

                elif step ==1:#判断auto还是control
                  if recvstr.find('auto')!=-1:
                        step=10
                        filesizestr = str(filesize)
                        limit = int(filesize/1024) + 1
                        self.request.send(filesizestr.encode(encoding="utf-8"))
                  elif recvstr.find('control')!=-1:
                        step=20
                        filesizestr = str(filesize)
                        self.request.send(filesizestr.encode(encoding="utf-8"))
                        limit = int(filesize/1024) + 1
                        cnt = 0
                  else:
                        self.request.send(b"cmderr:1")#未匹配到指令
                elif step ==10:#自动模式
                  if recvstr.find('start')==-1:
                        self.request.send(b"cmderr:1")#未匹配到指令
                        continue
                  delayms = 1000/ (int(re.sub(r'\D', "", recvstr)))
                  for i in range(limit):
                        buf = files.read(1024)
                        self.request.send(buf)
                        print('发送数据包:%d/%d' %(i+1,limit))
                        time.sleep(delayms/1000)
                  files.close()
                  print('传输结束')
                  break #传输结束
                elif step ==20:#手动模式
                  if cnt >= limit:
                        self.request.send(b"endoffile")
                        files.close()
                        print('传输结束')
                        break
                  if recvstr.find('next')!=-1:
                        cnt = cnt + 1
                        conbuf = files.read(1024)
                        self.request.send(conbuf)
                        print('控制传输:%d/%d'%(cnt,limit))
                        
                        time.sleep(0.03)
                  elif recvstr.find('resend')!=-1:
                        if cnt == 0:
                           conbuf = files.read(1024)
                           cnt = cnt + 1
                        self.request.send(conbuf)
                        print('重新传输:%d/%d'%(cnt,limit))
                        time.sleep(0.03)
                  elif recvstr.find('exit')!=-1:
                        files.close()
                        print('客户端断开')
                        break
                  else:
                        self.request.send(b"cmderr:1")#未匹配到指令

                else:
                  self.request.send(b"cmderr:-1")#未知错误
            except ConnectionResetError:
                break
      self.request.close()


if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('0.0.0.0', 6666), MyTcpHandler)
    server.serve_forever()


运行截图




sgh2zlx 发表于 2019-7-13 12:03

这个有学习价值{:1_921:}

yesit 发表于 2019-7-13 12:22

好贴,认真学习,谢谢楼主。

dimension4 发表于 2019-7-13 12:54

干货 收藏了{:1_921:}

洲总 发表于 2019-7-15 23:42

好~~~~!!!支持狐狸~~~~

Noire 发表于 2019-7-22 10:45

写的挺好的,收藏了.......

s58046 发表于 2019-7-22 11:49

牛批。写的很好,感谢分享
页: [1]
查看完整版本: 【python】OTA升级服务端程序,TCP连接,带文档