首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过TCP共享COM端口

通过TCP共享COM端口
EN

Stack Overflow用户
提问于 2010-04-07 13:38:02
回答 2查看 4.2K关注 0票数 3

通过TCP将COM端口共享给多个客户端的简单设计模式是什么?

例如,可以将坐标实时传输到远程主机的本地GPS设备。

因此,我需要一个程序来打开串行端口并接受多个TCP连接,如下所示:

代码语言:javascript
复制
class Program
{
    public static void Main(string[] args)
    {
        SerialPort sp = new SerialPort("COM4", 19200, Parity.None, 8, StopBits.One); 

        Socket srv = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        srv.Bind(new IPEndPoint(IPAddress.Any, 8000));
        srv.Listen(20);

        while (true)
        {
            Socket soc = srv.Accept();
            new Connection(soc);
        }
    }
}

然后,我需要一个类来处理连接的客户端之间的通信,让它们都能看到数据并保持同步,这样客户端命令才能按顺序接收:

代码语言:javascript
复制
class Connection
{
    static object lck = new object();
    static List<Connection> cons = new List<Connection>();

    public Socket socket;
    public StreamReader reader;
    public StreamWriter writer;

    public Connection(Socket soc)
    {
        this.socket = soc;
        this.reader = new StreamReader(new NetworkStream(soc, false));
        this.writer = new StreamWriter(new NetworkStream(soc, true));
        new Thread(ClientLoop).Start();
    }

    void ClientLoop()
    {
        lock (lck)
        {
            connections.Add(this);
        }
        while (true)
        {
            lock (lck)
            {
                string line = reader.ReadLine();
                if (String.IsNullOrEmpty(line))
                    break;

                foreach (Connection con in cons)
                    con.writer.WriteLine(line);
            }
        }
        lock (lck)
        {
            cons.Remove(this);
            socket.Close();
        }
    }
}

我正在努力解决的问题是如何促进SerialPort实例和线程之间的通信。

我不确定上面的代码是不是最好的方法,所以有没有人有其他的解决方案(越简单越好)?

EN

回答 2

Stack Overflow用户

发布于 2010-04-07 15:21:35

为什么要在这么低的级别(套接字)写?为什么不使用WCF作为客户端和服务器之间的通信,并提供一个更干净、强类型的接口,而不是对GPS设备的原始访问?

这样的设备通常最好独立于调用的客户端进行管理-即,您有自己的单独线程与GPS设备对话,以适当的时间间隔轮询它,并使用当前位置填充共享数据结构-而客户端进行服务调用,并从共享数据结构中获得数据。有时不可靠的设备连接的所有错误处理和恢复都是由GPS线程处理的,客户端不需要每个客户端都参与到这种糟糕的事情中来。它们可以进行非阻塞调用来获取状态更新,当GPS线程疯狂地尝试重新建立通信时,这些更新可能包括状态“位置不可用”。

因此,我将创建一个服务,该服务抽象处理此特定设备的细节,并为客户端提供一个干净的接口。例如,它可以提供像GetPosition()这样的服务,它返回像"GeoCoordinate“这样的类。这样,如果您需要支持其他位置感应设备,您可以添加它们,而无需对客户端代码进行任何更改。

代码语言:javascript
复制
                   GPS <--Serial--> Server <--WCF--> Clients

我有一个与数百个不同设备进行通信的系统,其中许多设备是通过串行端口和其他半可靠的连接进行通信的,这就是我使用的方法。参见http://blog.abodit.com

-根据您使用TELNET的其他要求:可能类似于:

创建一个线程来处理与设备本身的所有通信。

创建一个封装单个WorkItem的类-要发送的内容、响应和WaitHandle。

使用队列对来自客户端的请求进行排队。每个客户端都在WaitHandle上等待其响应准备就绪。

让单个通信线程从该队列中拉出工作项,将它们发送到GPS设备,获取响应,将响应存储在WorkItem中(或设置失败标志),然后设置等待句柄以告知WorkItem已完成。

如果请求传入的速度超过了GPS的处理能力,请添加代码,以便从设备上一次成功的请求开始,在较小的时间窗口内返回请求的缓存值。

实际上,您现在向所有客户端呈现了一个虚拟GPS设备,但是在内部,您正在序列化它们的所有请求(在一个队列上),并在单个线程上管理与GPS设备的通信,这样您就可以轻松地完成请求-响应周期,而不会受到干扰。

这还允许您很好地(在等待句柄上)超时,以通知客户端当前没有可用的响应。

票数 2
EN

Stack Overflow用户

发布于 2020-10-17 02:53:50

你有socat,ser2net和其他程序,但我的经验非常糟糕……不能正常工作。我自己做的这个python小程序,可以派上用场。更新端口,波特率...然后使用任何tcp客户端。如果不想用作自动可执行脚本,请删除第一行

代码语言:javascript
复制
#!/usr/bin/python

import socket
import sys
import serial

#open serial port
ser = serial.Serial('/dev/ttyAMA0', 115200, timeout=0)
#create socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

#bond to the port. Don't use localhost to accept external connections
server_address = ('', 2105)
print('starting up on {} port {}'.format(*server_address))
sock.bind(server_address)

#listen
sock.listen(1)

#loop
while True:
    #waits for a new connection
    print('waiting for a connection')
    connection, client_address = sock.accept()
    try:
        print('connection from', client_address)
        #continously send from serial port to tcp and viceversa
        connection.settimeout(0.1)
        while True:
            try:
                data = connection.recv(16)
                if data == '': break
                ser.write(data)
            except KeyboardInterrupt:
                connection.close()
                sys.exit()
            except Exception as e:
                pass
            received_data = ser.read(ser.inWaiting())
            connection.sendall(received_data)
    except Exception as e:
        print e

    finally:
        #clean up connection
        connection.close()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2590236

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档