设为首页收藏本站
查看: 498|回复: 0

【米尔瑞萨RZ/G2L开发板-创新应用】串口服务器实现

[复制链接]

3

主题

0

回帖

31

积分

新手上路

积分
31
感冒不喝水 发表于 2023-9-25 19:43:54 | 显示全部楼层 |阅读模式
继续在上一篇帖子的基础上实现完整的串口服务器【米尔瑞萨RZ/G2L开发板-创新应用】基于python的tcp、udp、串口收发使用 - 米尔RZ/G2L开发板 - 米尔科技论坛 - Powered by Discuz! (myir-tech.com)


本次需要实现的功能:
1、实现收到udp广播后,发送串口服务器配置信息;
2、收到tcp客户端发送来的数据后,自动转发到串口;
3、收到串口发送来的数据后,自动转发到tcp客户端;

功能实现:
1、收到UDP信息后,对信息内容进行过滤,如果结果匹配,则直接返回到发送端,代码如下:
  1. # -*- coding: utf-8 -*-

  2. import socket  # 导入socket模块
  3. import time  # 导入time模块
  4. import threading
  5. from config import *


  6. class udp(threading.Thread):
  7.     def __init__(self, ip: str = '', port: int = 9000):
  8.         threading.Thread.__init__(self)
  9.         self.ip = ip
  10.         self.port = port

  11.     def run(self):
  12.         cfg = config()
  13.         cfg.read()
  14.         # 创建一个套接字socket对象,用于进行通讯
  15.         # socket.AF_INET 指明使用INET地址集,进行网间通讯
  16.         # socket.SOCK_DGRAM 指明使用数据协议,即使用传输层的udp协议
  17.         server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  18.         # 接收来自任何IP的广播帧
  19.         address = (self.ip, self.port)
  20.         server_socket.bind(address)  # 为服务器绑定一个固定的地址,ip和端口
  21.         # server_socket.settimeout(10)  # 设置一个时间提示,如果10秒钟没接到数据进行提示

  22.         while True:
  23.             # 正常情况下接收数据并且显示,如果10秒钟没有接收数据进行提示(打印 'time out')
  24.             # 当然可以不要这个提示,那样的话把'try:' 以及 'except'后的语句删掉就可以了
  25.             try:
  26.                 # now = time.time()  # 获取当前时间
  27.                 # 接收客户端传来的数据 recvfrom接收客户端的数据,默认是阻塞的,直到有客户端传来数据
  28.                 # recvfrom 参数的意义,表示最大能接收多少数据,单位是字节
  29.                 # recvfrom返回值说明
  30.                 # receive_data表示接受到的传来的数据,是bytes类型
  31.                 # client  表示传来数据的客户端的身份信息,客户端的ip和端口,元组
  32.                 receive_data, client = server_socket.recvfrom(1024)
  33.                 # print(time.strftime('%Y-%m-%d %H:%M:%S',
  34.                 #                     time.localtime(now)))  # 以指定格式显示时间
  35.                 # print('来自客户端%s,发送的%s\n' % (client, receive_data))  # 打印接收的内容
  36.                 recv_str = str(receive_data, encoding="utf-8")
  37.                 if recv_str == 'where is myir serial port server?':
  38.                     ip_addr = cfg.ipv4
  39.                     serial_conf = ''
  40.                     for x in range(cfg.serial_count):
  41.                         serial_conf += cfg.tcp_ports[x]+','
  42.                         serial_conf += cfg.port[x]+','
  43.                         serial_conf += cfg.baudrate[x]+','
  44.                         serial_conf += cfg.parity[x]+';'
  45.                     server_socket.sendto(
  46.                         bytes(ip_addr+';'+serial_conf, encoding="utf8"), client)
  47.             except socket.timeout:
  48.                 print('time out')
复制代码
收到客户端发送的 where is myir serial port server? 后,发送串口及tcp服务器配置信息。
2、收到tcp客户端发送的信息后,自动转发到串口队列
注意:此处难点,需要将socket设置为非阻塞模式,否则无法转发串口收到的数据
  1. # -*- coding: utf-8 -*-

  2. import socket  # 导入socket模块
  3. import threading
  4. from queue import Queue
  5. import selectors
  6. import time


  7. class tcp(threading.Thread):
  8.     def __init__(self, tcp2sci: Queue, sci2tcp: Queue, ip: str = '', port: int = 9000):
  9.         threading.Thread.__init__(self)
  10.         self.ip = ip
  11.         self.port = port
  12.         self.tcp2sci = tcp2sci
  13.         self.sci2tcp = sci2tcp
  14.         # 创建 Selector 对象
  15.         self.sel = selectors.DefaultSelector()
  16.         self.clientAddr = 0
  17.         self.tcp_server_socket = 0

  18.     def run(self):
  19.         self.tcp_server_socket = socket.socket(
  20.             socket.AF_INET, socket.SOCK_STREAM)
  21.         address = (self.ip, self.port)
  22.         self.tcp_server_socket.bind(address)
  23.         self.tcp_server_socket.listen(128)
  24.         self.tcp_server_socket.setblocking(False)
  25.         # 将服务器套接字注册到 Selector 上
  26.         self.sel.register(self.tcp_server_socket,
  27.                           selectors.EVENT_READ, self.accept)

  28.         while True:
  29.             events = self.sel.select(timeout=0.001)
  30.             for key, mask in events:
  31.                 callback = key.data
  32.                 callback(key.fileobj, mask)
  33.             while not self.sci2tcp.empty():
  34.                 item = self.sci2tcp.get()
  35.                 if self.clientAddr != 0:
  36.                     self.tcp_server_socket.sendto(item, self.clientAddr)
  37.             time.sleep(0.001)

  38.         tcp_server_socket.close()

  39.     # 定义回调函数
  40.     def accept(self, sock, mask):
  41.         self.tcp_server_socket, self.clientAddr = sock.accept()
  42.         self.tcp_server_socket.setblocking(False)
  43.         self.sel.register(self.tcp_server_socket,
  44.                           selectors.EVENT_READ, self.read)

  45.     def read(self, sock, mask):
  46.         data = self.tcp_server_socket.recv(1024)
  47.         if data:
  48.             self.tcp2sci.put(data)
  49.         else:
  50.             self.sel.unregister(self.tcp_server_socket)
  51.             self.tcp_server_socket.close()
  52.             self.clientAddr = 0
复制代码
3、收到串口发送来的数据后,转发到tcp客户端
  1. import serial
  2. import os
  3. import socket  # 导入socket模块


  4. class config():
  5.     global cfg
  6.     def __init__(self):
  7.         self.serial_count = 1
  8.         self.path = './configurate/port_config'
  9.         self.device_name = 'serial_port_server'
  10.         self.ipv4 = self._get_ip_address()
  11.         self.udp_port = 9000
  12.         self.tcp_start_port = 5000
  13.         self.tcp_ports = []
  14.         self.port = []
  15.         self.baudrate = []
  16.         self.parity = []
  17.         for x in range(self.serial_count):
  18.             self.tcp_ports.append(x + self.tcp_start_port)
  19.             self.port.append('/dev/ttySC' + str(x))
  20.             self.baudrate.append('115200')
  21.             self.parity.append(serial.PARITY_NONE)

  22.     def save(self) -> int:
  23.         list = []
  24.         for x in range(self.serial_count):
  25.             list.append(str(self.tcp_ports[x]) + '\n')
  26.             list.append(self.port[x]+'\n')
  27.             list.append(self.baudrate[x]+'\n')
  28.             list.append(self.parity[x]+'\n')
  29.         if not os.path.exists('./configurate'):
  30.             os.mkdir('./configurate')
  31.         if os.path.exists(self.path):
  32.             os.remove(self.path)
  33.         with open(self.path, 'w') as file:
  34.             file.writelines(list)

  35.     def read(self) -> int:
  36.         if os.path.exists(self.path):
  37.             with open(self.path, 'r') as file:
  38.                 list = file.readlines()
  39.         index = 0
  40.         for x in range(self.serial_count):
  41.             self.tcp_ports[x] = list[index].replace('\n','')
  42.             index += 1
  43.             self.port[x] = list[index].replace('\n','')
  44.             index += 1
  45.             self.baudrate[x] = list[index].replace('\n','')
  46.             index += 1
  47.             self.parity[x] = list[index].replace('\n','')
  48.             index += 1
  49.         return 0
  50.    
  51.     def _get_ip_address(self) -> str:
  52.         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  53.         s.connect(("8.8.8.8", 80))
  54.         return str(s.getsockname()[0])
复制代码
4、另外需要读取配置文件
  1. import serial
  2. import os
  3. import socket  # 导入socket模块


  4. class config():
  5.     global cfg
  6.     def __init__(self):
  7.         self.serial_count = 1
  8.         self.path = './configurate/port_config'
  9.         self.device_name = 'serial_port_server'
  10.         self.ipv4 = self._get_ip_address()
  11.         self.udp_port = 9000
  12.         self.tcp_start_port = 5000
  13.         self.tcp_ports = []
  14.         self.port = []
  15.         self.baudrate = []
  16.         self.parity = []
  17.         for x in range(self.serial_count):
  18.             self.tcp_ports.append(x + self.tcp_start_port)
  19.             self.port.append('/dev/ttySC' + str(x))
  20.             self.baudrate.append('115200')
  21.             self.parity.append(serial.PARITY_NONE)

  22.     def save(self) -> int:
  23.         list = []
  24.         for x in range(self.serial_count):
  25.             list.append(str(self.tcp_ports[x]) + '\n')
  26.             list.append(self.port[x]+'\n')
  27.             list.append(self.baudrate[x]+'\n')
  28.             list.append(self.parity[x]+'\n')
  29.         if not os.path.exists('./configurate'):
  30.             os.mkdir('./configurate')
  31.         if os.path.exists(self.path):
  32.             os.remove(self.path)
  33.         with open(self.path, 'w') as file:
  34.             file.writelines(list)

  35.     def read(self) -> int:
  36.         if os.path.exists(self.path):
  37.             with open(self.path, 'r') as file:
  38.                 list = file.readlines()
  39.         index = 0
  40.         for x in range(self.serial_count):
  41.             self.tcp_ports[x] = list[index].replace('\n','')
  42.             index += 1
  43.             self.port[x] = list[index].replace('\n','')
  44.             index += 1
  45.             self.baudrate[x] = list[index].replace('\n','')
  46.             index += 1
  47.             self.parity[x] = list[index].replace('\n','')
  48.             index += 1
  49.         return 0
  50.    
  51.     def _get_ip_address(self) -> str:
  52.         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  53.         s.connect(("8.8.8.8", 80))
  54.         return str(s.getsockname()[0])
复制代码
5、在main中统一对所有线程进行初始化,并构建队列用于串口有tcp服务器之间传递信息
  1. # -*- coding: utf-8 -*-
  2. from udp import *
  3. from tcp import *
  4. from sci import *
  5. from config import *
  6. from threading import Thread
  7. from queue import Queue

  8. cfg = 0

  9. if __name__ == "__main__":
  10.     cfg = config()
  11.     # cfg.save()
  12.     cfg.read()
  13.     # 创建 Thread 实例
  14.     t1 = udp('', cfg.udp_port)
  15.     t1.start()

  16.     tcp_thread = []
  17.     serial_thread = []
  18.     for x in range(cfg.serial_count):
  19.         tcp2sci = Queue(maxsize=1000)
  20.         sci2tcp = Queue(maxsize=1000)
  21.         tcp_thread.append(
  22.             tcp(tcp2sci, sci2tcp, ip=cfg.ipv4, port=int(cfg.tcp_ports[x])))
  23.         # serial_thread.append(
  24.         #     sci(sci2tcp, tcp2sci, port=cfg.port[x], baudrate=cfg.baudrate[x], parity=cfg.parity[x]))

  25.     # 启动线程运行
  26.     for x in range(cfg.serial_count):
  27.         tcp_thread[x].start()
  28.         # serial_thread[x].start()

  29.     # 等待所有线程执行完毕
  30.     t1.join()  # join() 等待线程终止,要不然一直挂起
  31.     for x in range(cfg.serial_count):
  32.         tcp_thread[x].join()
  33.         # serial_thread[x].join()
复制代码
演示视频如下

https://www.bilibili.com/video/BV1KN411n7Jx/



回复

使用道具 举报

您需要登录后才可以回帖 登录

本版积分规则

Archiver|手机版|小黑屋|米尔科技论坛   

GMT+8, 2024-5-3 19:06 , Processed in 0.046164 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表