MicroPython Socket TCP链接记录二 全局采集数据
模拟测试 ,非生产日用, 生产最终选择使用简单的http来实现数据采集定时上报到后端,后端根据最后数据上传时间来判断设备是否掉线,毕竟花时间调试完socket了后,公司试用了下觉得不行那就浪费时间了
socketserver全局下发命令到客户端 完成数据采集并上传
因为手上暂时没有很多设备,所以先用电脑的异步客户端模拟设备,服务器发送ping命令,客户端返回pong+id
模拟设备掉线
代码如下
服务端
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2021/3/25 10:26
# @Author : Link
# @Site : 服务端
# @File : socket_server.py
# @Software: PyCharm
from socketserver import BaseRequestHandler, ThreadingTCPServer
import threading
from queue import Queue
from time import sleep
queue = Queue(maxsize=10)
connect_queen = {} # 每新建一个链接 则维护一个queue
def broadcast_queue_th():
while True:
inst = input("请输入下发命令(直接回车关闭链接)>>> :")
queue.put(inst)
inst = queue.get()
for _, _queue in connect_queen.items():
_queue.put(inst)
class Handler(BaseRequestHandler):
# def handle(self) -> None:
# address, pid = self.client_address
# print("%s connected! pid: %s" % (address, pid))
# while True:
# try:
# data = self.request.recv(1024)
# if not data: break
# print('->pid:%s say client:%s' % (pid, data))
# self.request.send(data.upper())
# except ConnectionError:
# print('->pid:%s close connect' % (pid))
# break
# print("request close\n")
# self.request.close()
# 启动一个用于发布全局数据的链接
def handle(self) -> None:
address, pid = self.client_address
connect_queen[pid] = Queue(maxsize=2)
while True:
try:
data = connect_queen[pid].get()
if not data: break #断开链接
self.request.send(data.encode('utf-8'))
recv = self.request.recv(30).decode("utf-8") # 等待数据 阻塞
if recv:
print(recv)
self.request.send("33".encode('utf-8'))
sleep(.2)
except ConnectionError:
break
del connect_queen[pid]
self.request.close()
if __name__ == '__main__':
# 启动数据发布进程
th = threading.Thread(target=broadcast_queue_th, name="thi")
th.start()
# 启动服务器
server = ThreadingTCPServer(('0.0.0.0', 8080), Handler)
server.serve_forever() # 链接循环
客户端
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2021/3/26 15:56
# @Author : Link
# @Site : 客户端
# @File : socket_client.py
# @Software: PyCharm
import socket
import asyncio
import random
# 创建十个测试链接
clients = [socket.socket(socket.AF_INET, socket.SOCK_STREAM) for _ in range(10)]
for client in clients:
client.connect(('127.0.0.1', 8080))
async def client_connect_server_send(client, i):
while True:
client.send(f'hello{i}'.encode('utf-8'))
print(client.recv(1024).decode("utf-8"))
await asyncio.sleep(.5)
# client.close()
async def client_connect_server_recv(client, i):
sl = 0
sl_t = random.randint(10, 20)
equipment = "micro{}".format(i)
while True:
sl += 1
if sl >= sl_t:
print("micro{} connect close!".format(i))
break
data = client.recv(36).decode("utf-8") # 服务器断开链接后会一直返回空,没有断开就会阻塞住
if data:
# 获取到服务器发送来的全局指令
send_data = equipment_exec(equipment, data).encode('utf-8')
client.send(send_data)
# 服务器上传数据后解析成功返回33
res = client.recv(10).decode("utf-8")
if res == "33":
print("success")
else:
print(res)
else:
print("micro{} connect close!".format(i))
break
await asyncio.sleep(.5)
client.close()
def equipment_exec(equipment: str, inst: str) -> str:
"""
每次获取到服务器的指令后 都要进行返回
"""
if inst == "hello":
return "this is %s" % equipment
if inst == "ping":
return "pong %s" % equipment
return "nothing"
if __name__ == '__main__':
loop = asyncio.get_event_loop()
tasks = [client_connect_server_recv(client=client, i=index) for index, client in enumerate(clients)]
loop.run_until_complete(asyncio.wait(tasks))
先启动服务端,再启动客户端,手动在客户端发送命令测试,客户端在接收到十到二十次数据后会断线