socket 实现单一串口共享读写操作
前提:物理串口连接到PC上,通过串口号被PC唯一识别。
此时,物理串口通过该串口号仅能被单一线程或进程实例并占用,
其他线程或进程不能再通过该串口号与物理串口通信。这个暂称为串口独占性。
解决思路:
核心思想:利用计算机软件中的socket编程,一个socket server 可以连接多个socket client,由socket server 完成多个socket client与物理串口的通信。
实现过程:
1、编程语言根据物理串口的串口号实例化一个串口操作类,串口操作类负责与物理串口通信。建立串口写线程和串口读线程。其中,串口读线程不断收取物理串口输出,并存放到读缓存。串口写线程不断从写缓存取命令,由其不断发往物理串口。
2、建立一个可靠的Socket Server,当有Socket Client连接时,由其将读缓存中的数据发给Socket Client,并不断收取Socket Client发来的命令,存放到写缓存中。
3、编程语言线程/进程通过建立Socket Client连接到Socket Server,既可实现多个线程/进程
与物理串口的通信
以下没有实现缓存机制,而是将读取到的串口数据放入队列:
socket server
#!/usr/bin/python
# -*- coding: utf-8 -*- import socket
import psutil
import traceback
import threading
import SocketServer
import json
import sys
import Queue
import time from serial import Serial
from SocketServer import StreamRequestHandler as SRH
from CustomStringIO import CustomStringIO SERIALCOMNUM = {} class MainHandler(SRH): def handle(self):
try:
print 'Client [%s] is Connected To The Server On Port [%s].' % (self.client_address[0], self.client_address[1])
self.keep_alive = True
while self.keep_alive:
data = self.request.recv(4096 * 3)
if not data:
break
data_json = json.loads(data)
if "RequestType" in data_json:
if data_json["RequestType"] == "DevSerialHandle":
if "Port" in data_json["Args"]:
self.dev_serial_handler(data_json, close_timeout=60)
break
else:
break
except Exception as e:
traceback.print_exc()
finally:
print '<------ SerialSocketServer handle request finish ------>' def dev_serial_handler(self, data_json, close_timeout=60):
self.read_queue = Queue.Queue()
read_id = str(time.time())
if data_json["Args"]['Port'] in SERIALCOMNUM:
self.dev_serial = SERIALCOMNUM[data_json["Args"]["Port"]]['serial']
self.dev_serial.client_buffer.update({read_id:self.read_queue})
SERIALCOMNUM[data_json["Args"]["Port"]]['count'] += 1
else:
self.dev_serial = SerialHandle(data_json["Args"]['Port'])
self.dev_serial.client_buffer.update({read_id:self.read_queue})
SERIALCOMNUM.update({data_json["Args"]['Port']:{'serial':self.dev_serial,'count':1}}) print str(SERIALCOMNUM)
th_dev_serial_read = threading.Thread(target=self.read_dev_serial)
th_dev_serial_read.start() is_recv_data_none = False
while self.keep_alive:
try:
data = self.request.recv(4096 * 3)
print 'your input is %s' % str(data)
except socket.error:
self.keep_alive = False
print "close dut serial"
break
else:
if data:
self.dev_serial.write(data)
end_time = time.time() + close_timeout
# socket client 关闭后,self.request.recv会一直收到空字符串,等待一段时间后,关闭连接
else:
if is_recv_data_none == False:
is_recv_data_none = True
end_time = time.time() + close_timeout
if time.time() > end_time:
print 'wait for webbroswer connect timeout'
print "close dut serial"
self.keep_alive = False
break if SERIALCOMNUM[data_json["Args"]["Port"]]['count'] > 0:
SERIALCOMNUM[data_json["Args"]["Port"]]['count'] -= 1
SERIALCOMNUM[data_json["Args"]["Port"]]['serial'].client_buffer.pop(read_id)
print str(SERIALCOMNUM) if SERIALCOMNUM[data_json["Args"]["Port"]]['count'] <= 0:
print 'clear serial start'
SERIALCOMNUM[data_json["Args"]["Port"]]['serial'].close()
if data_json["Args"]['Port'] in SERIALCOMNUM:
SERIALCOMNUM.pop(data_json["Args"]["Port"]) def read_dev_serial(self):
try:
while self.keep_alive:
# serial_log = self.dev_serial.read()
serial_log = self.read_queue.get()
self.request.send(serial_log)
except socket.error:
pass class ThreadingServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): def _threading_server(self):
pass class SerialSocketServer(object): def __init__(self, port=33233):
self.server = None
self.port = 33233 def start(self):
netcard_ips = self.get_netcard()
for netcard_ip in netcard_ips:
host = netcard_ip[1] try:
port = self.port
addr = (host, port)
self.server = ThreadingServer(addr, MainHandler)
self.server.allow_resuse_address = True
server_thread = threading.Thread(target=self.server.serve_forever)
server_thread.daemon = True
server_thread.start()
print "Starting Serial Socket Successfully!"
while True:
try:
INPUT = raw_input()
except KeyboardInterrupt:
sys.exit(0)
break
except EOFError:
print 'Unknown End of file!'
continue except Exception, e:
print "Starting Serial Socket Server Fail:%s" % e def stop(self):
print "Shutdown Slave Socket Server!"
if self.server != None:
self.server.shutdown()
self.server.server_close() def get_netcard(self):
"""获取网卡信息和ip地址 """
netcard_info = []
info = psutil.net_if_addrs()
for k, v in info.items():
for item in v:
if item[0] == 2 and not (item[1] == '127.0.0.1' or item[1] == '192.168.2.201'):
netcard_info.append((k, item[1]))
return netcard_info class SerialHandle(): def __init__(self, port=None, baudrate=115200, timeout=30, *args, **kargs):
self.serial = Serial(port=port, baudrate=baudrate, timeout=timeout, *args, **kargs)
self.is_running = True
self.read_buffer = ""
self.write_queue = Queue.Queue()
self.read_buffer = CustomStringIO(4096)
th_wt = threading.Thread(target=self.__write)
th_wt.start()
th_rd = threading.Thread(target=self.__read)
th_rd.start()
self.client_buffer = {} def read(self, read_id):
return self.read_buffer.getvalue() def __read(self):
while self.is_running:
serial_log = self.serial.readline()
for key, value in self.client_buffer.items():
self.client_buffer[key].put(serial_log) def write(self,write_string):
self.write_queue.put(write_string) def __write(self):
while self.is_running:
write_string = self.write_queue.get()
self.serial.write(write_string) def close(self):
self.is_running = False
self.serial.close()
print 'close serial' if __name__ == '__main__':
SerialSocketServer().start()
启动服务器:python serial_socket_server.py
socket client :
import threading
import socket
import traceback
import json
import sys
import re
import Queue class DevSerialLoadClient(threading.Thread): def __init__(self, node_ip, server_port=33233, serial_port="COM19"):
threading.Thread.__init__(self)
self.slave_serial_serial_server = node_ip
self.server_port = server_port
self.serial_port = serial_port
self.bufsize = 4096 * 4
self.setDaemon(True)
self._is_running = True
self._is_establish_connection = False
self.client = None def connect(self):
try:
addr = (self.slave_serial_serial_server, self.server_port)
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.connect(addr)
self._is_establish_connection = True
except Exception as e:
self._is_establish_connection = False
print "Create Socket Connect Fail: %s" % e def run(self):
self.connect()
if self.is_establish_connection:
request_msg = json.dumps({"RequestType":"DevSerialHandle","Args":{"Port":self.serial_port}})
self.client.send(request_msg) while self._is_running:
try:
response = self.client.recv(self.bufsize)
if not response:
continue
handle_response = re.compile('[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f|\\xff]').sub(' ', response.decode('unicode-escape'))
print '%s' % str(handle_response)
except socket.error:
print 'socket error'
self.connect()
except:
traceback.print_exc()
print "------stop dev serial communication------"
self.close() def close(self):
try:
if self.client:
self.client.shutdown(socket.SHUT_RDWR)
self.client.close()
except Exception, e:
print "close socket client Error[%s]" % str(e) @property
def is_establish_connection(self):
return self._is_establish_connection def stop(self):
self._is_running = False if __name__ == '__main__':
import getopt
opts, args = getopt.getopt(sys.argv[1:], "h:s:")
server_ip = "localhost"
server_port = 33233
serial_port = None
for op, value in opts:
if op == "-h":
server_ip = value
if op == '-s':
serial_port = value if not serial_port:
print 'should provide serial port args: like -p COM19' dev_serial = DevSerialLoadClient(node_ip=server_ip, server_port=server_port, serial_port=serial_port)
dev_serial.start()
while True:
try:
INPUT = raw_input()
dev_serial.client.send(INPUT+'\n')
except KeyboardInterrupt:
sys.exit(0)
break
except EOFError:
print 'Unknown End of file!'
continue
启动socket client:python serial_socket_client.py -h 对端ip -s 串口号
在命令行可向要连接的串口发送指令。
可建立多个client读写同一串口,所有client都可向串口发送数据;当一个client向串口输入数据后,其他client都可以收到串口的打印
socket 实现单一串口共享读写操作的更多相关文章
- c#读写共享内存操作函数封装
原文 c#读写共享内存操作函数封装 c#共享内存操作相对c++共享内存操作来说原理是一样,但是c#会显得有点复杂. 现把昨天封装的读写共享内存封装的函数记录下来,一方面希望给需要这块的有点帮助,另一方 ...
- VC++ 共享内存读写操作
此解决方案含两个工程文件,一个是写操作工程文件,即把任意字符串写入创建的共享内存里,另外一个读操作工程文件,则是读取共享内存里的数据,从而实现了进程之间的共享内存读写操作. 源码下载
- MM32Flash读写操作(兼容STM32)
MM32Flash读写操作(兼容STM32) Flash基础描述 思维导图 编程实现读写操作 主函数结构 #include "delay.h" #include "sys ...
- OpenCV 编程简单介绍(矩阵/图像/视频的基本读写操作)
PS. 因为csdn博客文章长度有限制,本文有部分内容被截掉了.在OpenCV中文站点的wiki上有可读性更好.而且是完整的版本号,欢迎浏览. OpenCV Wiki :<OpenCV 编程简单 ...
- 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...
- C# System.IO和对文件的读写操作
System.IO命名空间中常用的非抽象类 BinaryReader 从二进制流中读取原始数据 BinaryWriter 从二进制格式中写入原始数据 BufferedStream 字节流的临时存储 ...
- [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么? http://www.52im.net/thread-1732-1-1.html 1.引言 本文接上篇<脑残式网 ...
- C#读写三菱Fx PLC 使用Fx 串口协议 读写Fx3U设备
本文将使用一个Github开源的组件库技术来读写三菱 FX PLC,使用的是基于串口的实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 github地 ...
- 一个I/O线程可以并发处理N个客户端连接和读写操作 I/O复用模型 基于Buf操作NIO可以读取任意位置的数据 Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel 事件驱动消息通知观察者模式
Tomcat那些事儿 https://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650860016&idx=2&sn=549 ...
随机推荐
- Open quote is expected for attribute "{1}" associated with an element type "column".
这个的错误的意思很简单:就是自己的配置文件是否缺少""号
- 行盒(line box)垂直方向的属性详解:从font-size、line-height到vertical-align
视觉格式化模型 在一个文档中,每个元素都被表示为0.1或多个矩形的盒子.确定这些盒子的尺寸, 属性 --- 像它的颜色,背景,边框方面 --- 和位置是渲染引擎的目标.① 在CSS中,使用标准盒模型描 ...
- Koa源码分析(一) -- generator
Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: 1. Koa源码分析(一) -- generator 2. Koa源码分析(二) -- co的实现 ...
- 【Python】 Python3 环境搭建
Python是一种计算机程序设计语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的.大型项目的开发. Windo ...
- thinkphp 5 使用oss
简单的tp5中上传到 图片到oss我本地开发环境为:WAMP;php版本:5.6.19TP版本:5.1.13 1.使用composer 安装 composer require aliyuncs/oss ...
- T-4-java核心API-集合类
一.集合 用于存储类型一致的一组对象的数据结构. 类似于数组,但是集合提供了操作算法:集合=数据存储+操作算法.集合的用途极其广泛,如歌曲列表,联系人列表对话记录等. 集合比数组多了操作算法,便于提高 ...
- final,static,abstract
一.final 1.可以修饰属性,表示常量,其值在运行期间不允许改变.常量必须赋初始值,初始值可以在声明出,构造方法的任意一个地方赋 优点:增强程序的可读性,可维护性 2.可以修饰方法,表示该方法不能 ...
- Meanshift均值漂移算法
通俗理解Meanshift均值漂移算法 Meanshift车手?? 漂移?? 秋名山??? 不,不,他是一组算法, 今天我就带大家来了解一下机器学习中的Meanshift均值漂移. Mea ...
- firebug定位工具很强大
firebug这个工具很强大,如果实在找不到自己想要的元素,就安装firebug这个定位工具妥妥的
- 第47章:MongoDB-用户管理
①用户管理 在MongoDB里面默认情况下只要是进行连接都可以不使用用户名与密码,因为要想让其起作用,则必须具备以下两个条件: ·条件一:服务器启动的时候打开授权认证: ·条件二:需要配置用户名和密码 ...