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都可以收到串口的打印

时间: 2024-10-11 04:45:13

socket 实现单一串口共享读写操作的相关文章

VC++ 共享内存读写操作

此解决方案含两个工程文件,一个是写操作工程文件,即把任意字符串写入创建的共享内存里,另外一个读操作工程文件,则是读取共享内存里的数据,从而实现了进程之间的共享内存读写操作. 源码下载

Android数据存储——文件读写操作(File)

Android文件读写操作 一.文件的基本操作 Android中可以在设备本身的存储设备或外接的存储设备中创建用于保存数据的文件.在默认状态下,文件是不能在不同程序间共享的. 当用户卸载您的应用程序时,这些文件删除. 文件存储数据可以通过openFileOutput方法打开一个文件(如果这个)文件不存在就自动创建这个文件),通过load方法来获取文件中的 数据,通过deleteFile方法删除一个指定的文件. 1,常用方法介绍: File是通过FileInputStream和FileOutput

hdf5格式的matlab读写操作

最近要用caffe处理一个multi-label的回归问题,就是输出是一个向量,不是一个具体的数值,这个时候之前的leveldb格式就不凑效了,因为caffe源代码里面默认label是一个数值,网上搜了下,都说hdf5格式可以解决这个问题 在caffe里面,有一个hdf5的datalayer作为数据输入,从源代码来看,对于label的维数没做限制,剩下的问题就是如何生成hdf5的数据,目前只是找到了github上的一个人共享的用matlab写的hdf5数据的读写操作,在这我把代码粘贴出来 tes

[转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么? http://www.52im.net/thread-1732-1-1.html 1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机网络编程的基础,TCP/UDP收发消息都靠它.我们熟悉的web服务器底层依赖它,我们用到的MySQL关系数据库.Redis内存数据库底层依赖它.我们用微信和别

文件的新建、定位、截短和读写操作

1.创建一个新文件,创建新文件除了可以使用open函数之外还可以用creat()函数. 创建文件函数 creat(const char * pathname, mode_t mode) 头文件 :#include <fcntl.h> 参数说明:第一个参数pathname同open函数的第一个参数具有同样的意义,区别在于这是需要创建的文件的地址而不是需要打开文件的地址,第二个参数mode是新建文件的访问权限. 返回值:成功返回1,失败返回-1. 函数说明:creat()函数能够创建一个新的文件,

对SD卡的读写操作-保存用户登录密码

import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import android.content.Context; import android.os.Environment; public class Fileservice { /** * 存储用

oracle读写文件--利用utl_file包对磁盘文件的读写操作

摘要: 用户提出一个需求,即ORACLE中的一个表存储了照片信息,字段类型为BLOB,要求能导出成文件形式. 本想写个C#程序来做,后来想起ORACLE有很多包,功能很好很强大,于是网上参考了些文章完成了. 主要是用了ORACLE的两个包:UTL_FILE和DBMS_LOB. 实现过程: 第一步:以管理员用户登陆设置可操作目录 --CREATE DIRECTORY privilege is granted only to SYS and SYSTEM by default. create or

java文件读写操作类

借鉴了项目以前的文件写入功能,实现了对文件读写操作的封装 仅仅需要在读写方法传入路径即可(可以是绝对或相对路径) 以后使用时,可以在此基础上改进,比如: 写操作: 1,对java GUI中文本框中的内容进行捕获,放在txt文本文档中 2,对各种类型数据都以字符串的形式逐行写入 3,对全局数组的内容进行写入 读操作: 获取文件行数 对逐行字符串型数据进行类型转换,放入二维数组中 为后面算法处理提供入口,但是要小心的是:不可以将行数用全局变量做计数器,否则每次读入是全局变量累加出错,应重新开始读取

python excel读写操作

1.读操作 xlrd 下载地址:https://pypi.python.org/pypi/xlrd 使用代码 # encoding : utf-8 #设置编码方式 import xlrd #导入xlrd模块 #打开指定文件路径的excel文件 xlsfile = r'D:\AutoPlan\apisnew.xls' book = xlrd.open_workbook(xlsfile) #获得excel的book对象 #获取sheet对象,方法有2种: sheet_name=book.sheet_