嵌入式开发日记(9)——多线程与socket通信
尝试用多线程,socket网络编程,心跳检测机制,实时绘图,丢包检测机制,校验位检测,超时重传机制, 数据库存储等功能优化项目
多线程与socket编程:
参考链接:
https://blog.csdn.net/qq_39687901/article/details/81531101 Python多线程socket通信
https://www.runoob.com/python3/python3-multithreading.html Python多线程
首先,需要明白的是socket的accept和recv这两个方法是阻塞线程的。这就意味着我们需要新开线程来处理这两个方法。
具体的程序流程大概是这样的:
1.新开一个线程用于接收新的连接(socket.accept())
2.当有新的连接时,再新开一个线程,用于接收这个连接的消息(socket.recv())
3.主线程做为控制台,接收用户的输入,进行其他操作
也就是说,服务端需要为每一个连接创建一个线程。
服务端(上位机)功能:
1 创建接口
2 接收多客户端数据
3 分别记录到本地txt
import serial
import socket # 导入 socket 模块
from threading import Thread
import os
import timeADDRESS = ('127.0.0.1', 8712) # 绑定地址g_socket_server = None # 负责监听的socketg_conn_pool = [] # 连接池def init():"""初始化服务端"""global g_socket_serverg_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建 socket 对象g_socket_server.bind(ADDRESS)g_socket_server.listen(5) # 最大等待数(有很多人理解为最大连接数,其实是错误的)print("服务端已启动,等待客户端连接...")def accept_client():"""接收新连接"""while True:client, _ = g_socket_server.accept() # 阻塞,等待客户端连接# 加入连接池g_conn_pool.append(client)# 给每个客户端创建一个独立的线程进行管理thread = Thread(target=message_handle, args=(client,))# 设置成守护线程thread.setDaemon(True)thread.start()def message_handle(client):"""消息处理"""client.sendall("连接服务器成功!".encode(encoding='utf8'))Time = time.strftime("%Y-%m-%d") + '设备'+str(g_conn_pool.index(client)) # 记录当前时间file_write_obj = open(Time + ".txt", 'w') # 建立记录文件file_write_obj.writelines("=================================================")file_write_obj.write('\n')file_write_obj.writelines(time.strftime("%Y-%m-%d %X "))file_write_obj.write('\n')file_write_obj.writelines("===============================================")file_write_obj.write('\n')while True:#bytes = ''bytes = client.recv(1024)# print("客户端消息:", bytes.decode(encoding='utf8'))file_write_obj.writelines(str(bytes.decode(encoding='utf8'))) #记录到本地file_write_obj.write('\n') if len(bytes) == 0:client.close()# 删除连接g_conn_pool.remove(client)print("有一个客户端下线了。")file_write_obj.close()breakif __name__ == '__main__': # 主函数init()# 新开一个线程,用于接收新连接thread = Thread(target=accept_client)thread.setDaemon(True)thread.start()# 主线程逻辑while True:cmd = input("""--------------------------
输入1:查看当前在线人数
输入2:给指定客户端发送消息
输入3:关闭服务端""")if cmd == '1':print("--------------------------")print("当前在线人数:", len(g_conn_pool))elif cmd == '2':print("--------------------------")while (1):index, msg = input("请输入“索引,消息”的形式:").split(",")g_conn_pool[int(index)].sendall(msg.encode(encoding='utf8'))elif cmd == '3':exit()
客户端(Arm板)功能:
1 数据的处理
2 数据的回传
import socket # 导入 socket 模块
import serialACCData = [0.0] * 8
GYROData = [0.0] * 8
AngleData = [0.0] * 8 # 定义三个数组,分别存储加速度角速度与角度的值FrameState = 0 # 通过0x后面的值判断属于哪一种情况
Bytenum = 0 # 读取到这一段的第几位
CheckSum = 0 # 求和校验位def DueData(inputdata): # 新增的核心程序,对读取的数据进行划分,各自读到对应的数组里global FrameState # 在局部修改全局变量,要进行global的定义global Bytenumglobal CheckSumresult = []for data in inputdata: # 在输入的数据进行遍历if FrameState == 0: # 当未确定状态的时候,进入以下判断if data == 0x55 and Bytenum == 0: # 0x55位于第一位时候,开始读取数据,增大bytenumCheckSum = dataBytenum = 1continueelif data == 0x51 and Bytenum == 1: # 在byte不为0 且 识别到 0x51 的时候,改变frameCheckSum += dataFrameState = 1Bytenum = 2elif data == 0x52 and Bytenum == 1: # 同理CheckSum += dataFrameState = 2Bytenum = 2elif data == 0x53 and Bytenum == 1:CheckSum += dataFrameState = 3Bytenum = 2elif FrameState == 1: # acc #已确定数据代表加速度if Bytenum < 10: # 读取8个数据ACCData[Bytenum - 2] = data # 从0开始CheckSum += dataBytenum += 1else:if data == (CheckSum & 0xff): # 假如校验位正确#s.send(get_acc(ACCData).encode('utf8'))result.append(get_acc(ACCData))CheckSum = 0 # 各数据归零,进行新的循环判断Bytenum = 0FrameState = 0elif FrameState == 2: # gyroif Bytenum < 10:GYROData[Bytenum - 2] = dataCheckSum += dataBytenum += 1else:if data == (CheckSum & 0xff):#s.send(get_gyro(GYROData).encode('utf8'))result.append(get_gyro(GYROData))CheckSum = 0Bytenum = 0FrameState = 0elif FrameState == 3: # angleif Bytenum < 10:AngleData[Bytenum - 2] = dataCheckSum += dataBytenum += 1else:if data == (CheckSum & 0xff):#s.send(get_angle(AngleData).encode('utf8'))result.append(get_angle(AngleData))CheckSum = 0Bytenum = 0FrameState = 0return resultdef get_acc(datahex): # 加速度axl = datahex[0]axh = datahex[1]ayl = datahex[2]ayh = datahex[3]azl = datahex[4]azh = datahex[5]k_acc = 16acc_x = (axh << 8 | axl) / 32768 * k_accacc_y = (ayh << 8 | ayl) / 32768 * k_accacc_z = (azh << 8 | azl) / 32768 * k_accif acc_x >= k_acc:acc_x -= 2 * k_accif acc_y >= k_acc:acc_y -= 2 * k_accif acc_z >= k_acc:acc_z -= 2 * k_accresa = [str(acc_x), str(acc_y), str(acc_z)]return 'ACC:'+ ' '.join(resa)def get_gyro(datahex): # 陀螺仪wxl = datahex[0]wxh = datahex[1]wyl = datahex[2]wyh = datahex[3]wzl = datahex[4]wzh = datahex[5]k_gyro = 2000gyro_x = (wxh << 8 | wxl) / 32768 * k_gyrogyro_y = (wyh << 8 | wyl) / 32768 * k_gyrogyro_z = (wzh << 8 | wzl) / 32768 * k_gyroif gyro_x >= k_gyro:gyro_x -= 2 * k_gyroif gyro_y >= k_gyro:gyro_y -= 2 * k_gyroif gyro_z >= k_gyro:gyro_z -= 2 * k_gyroresg = [str(gyro_x), str(gyro_y),str(gyro_z)]return 'GYRO:'+ ' '.join(resg)def get_angle(datahex): # 角度rxl = datahex[0]rxh = datahex[1]ryl = datahex[2]ryh = datahex[3]rzl = datahex[4]rzh = datahex[5]k_angle = 180angle_x = (rxh << 8 | rxl) / 32768 * k_angleangle_y = (ryh << 8 | ryl) / 32768 * k_angleangle_z = (rzh << 8 | rzl) / 32768 * k_angleif angle_x >= k_angle:angle_x -= 2 * k_angleif angle_y >= k_angle:angle_y -= 2 * k_angleif angle_z >= k_angle:angle_z -= 2 * k_angleresan = [str(angle_x), str(angle_y), str(angle_z)]return 'ANGLE:'+ ' '.join(resan)if __name__ == '__main__': # 主函数ser = serial.Serial("com5", 115200, timeout=0.5) # 打开端口,改到循环外print(ser.is_open)s = socket.socket() # 创建 socket 对象s.connect(('127.0.0.1', 8712))print(s.recv(1024).decode(encoding='utf8'))while True:datahex = ser.read(33) # 不用hex()转化,直接用read读取的即是16进制news =' | '.join(DueData(datahex))s.send(news.encode('utf8'))
以上功能,实现了上位机以多线程连接多个客户端,并且分别记录到本地文件的过程。
Github地址:https://github.com/hanjintao1996/jy61-/blob/master/%E5%AE%A2%E6%88%B7%E7%AB%AF%E2%80%94%E2%80%94%E7%94%A8socket%E4%BC%A0%E8%BE%93%E5%B9%B6%E8%AE%B0%E5%BD%95
嵌入式开发日记(9)——多线程与socket通信相关推荐
- 递归锁、信号量、GIL锁、基于多线程的socket通信和进程池线程池
递归锁.信号量.GIL锁.基于多线程的socket通信和进程池线程池 递归锁 死锁现象:是指两个或两个以上的进程和线程因抢夺计算机资源而产生的一种互相等待的现象 from threading impo ...
- 使用Petalinux实现ZYNQ的linux程序开发(实现简单的socket通信程序)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 (一)实现功能及开发环境 一.实现功能 二.开发环境 (二)实现步骤 一.开发环境搭建 1.设置Ubuntu 和 Windo ...
- vs c语言 多线程demo,一个多线程的Socket通信Demo(C语言实现)
-----------这是客户端程序-------------- #include "stdio.h" #include "winsock2.h" #inclu ...
- ABB 机器人二次开发另一种方式 socket通信
前言: 前面我们说了一种方式是用 abb 官方提供的 c# sdk,只有c#的 所以有一定的局限性 PC SDK 还有另一种方法 写RAPID 代码 建立客户端/服务器 通过socket 与上位机通信 ...
- 嵌入式开发日记(8)——用python实现FIR滤波(未完待续)
第一阶段的方法是根据单位时间内的加速度绝对值差值来判断震颤程度,存在很多问题.因此设想采用更加高级的算法来加以改进. 这部分的主要工作有: 1 学习数字信号处理的滤波算法,重点学习python下使用 ...
- 应聘linux/ARM嵌入式开发岗位
**************************************************************** 因为发在中华英才和智联招聘没有人采我所以我 在这里发布我的个人简历希望 ...
- Socket通信学习(二):序列化与反序列化
Socket通信学习(二):序列化与反序列化 HoloLens的开发最近需要用到Socket通信,所以创建本系列进行记录,欢迎大家批评指正! 前言 Socket通信的默认发送的数据为byte[]类型, ...
- Socket通信学习(一):Socket通信原理
Socket通信学习(一):Socket通信原理 HoloLens的开发最近需要用到Socket通信,所以创建本系列进行记录,欢迎大家批评指正! 前言 应用Socket进行设备通信,首先需要了解Soc ...
- 嵌入式开发的三大平台和开发流程
嵌入式开发是指在嵌入式系统下进行软硬件以及综合开发.嵌入式系统是以微处理器和软件为核心:可以灵活.便捷地嵌入到其他应用系统,具有很强的嵌入性.常见的如手表.手机.照相机.电脑.汽车等,都使用了嵌入式系 ...
最新文章
- tcp retransmission 出现的原因_浅谈TCP的keepalive机制
- 福布斯 : 企业市场Chrome任重道远
- Java 类加载体系之 ClassLoader 双亲委托机制
- 单源最短路——dijkstra算法
- Django—模板渲染
- django html5 关系,Django REST FrameWork中文教程5:关系和超链接API
- 【MySQL】计算 TPS,QPS 的方式
- nginx监听事件流程
- Httpd 使用ip可以访问,localhost和127.0.0.1不能访问
- lol最强最高输出的adc_LOL:官方公布ADC的输出能力,最强最弱都是谁?德莱文不是最高的...
- 程序员如何从初中级历练为高级开发者?
- powerquery分组_Power Query 基本功能使用
- python写图片爬取软件_python抓取整个网站图片
- 中石油职称计算机报名,中石油职称计算机考试题库(单选).doc
- 恒生UFX 统一接入介绍
- 解决Jenkins一直用户名或密码错误
- mindmanager2021下载 最新版如何更新
- android多点触控,图片的拖拽与放大缩小
- 书山有路勤为径,学海无涯苦作舟
- send disconnect: Broken pipe SFTP 登录