3

複数のクライアントが TCP 経由で COM ポートを共有するための単純な設計パターンは何ですか?

たとえば、座標をリモート ホストにリアルタイムで送信できるローカル GPS デバイスなどです。

したがって、シリアルポートを開き、次のような複数の TCP 接続を受け入れるプログラムが必要です。

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);
        }
    }
}

次に、接続されたクライアント間の通信を処理するクラスが必要になります。これにより、すべてのクライアントがデータを参照できるようになり、クライアント コマンドが順番に受信されるように同期が維持されます。

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 インスタンスとスレッド間の通信を容易にする方法です。

上記のコードが最善の方法であるとは確信していないので、別の解決策を持っている人はいますか (シンプルなほど良い)?

4

2 に答える 2

2

なぜこのような低レベル (ソケット) で書くのでしょうか? クライアントとサーバー間の通信に WCF を使用し、GPS デバイスへの生のアクセスではなく、より明確で厳密に型指定されたインターフェイスを提供してみませんか?

このようなデバイスは、多くの場合、呼び出しを行うクライアントとは独立して管理するのが最適です。つまり、クライアントがサービス呼び出しを行っている間、GPS デバイスと通信し、適切な間隔でポーリングし、共有データ構造に現在の位置を入力する独自のスレッドを用意します。共有データ構造からデータが提供されます。場合によっては信頼できないデバイス接続のすべてのエラー処理と回復は GPS スレッドによって処理され、クライアントはそれぞれそのような厄介なことに関与する必要はありません。GPS スレッドが必死に通信を再確立しようとしている間、非ブロック呼び出しを行ってステータスの更新を取得できます。これらの更新には、「位置を利用できません」というステータスが含まれる場合があります。

そこで、この特定のデバイスの処理の詳細を抽象化し、クライアントにクリーンなインターフェイスを提供するサービスを作成します。たとえば、「GeoCoordinate」などのクラスを返す GetPosition() などのサービスを提供する場合があります。そうすれば、他の位置検出デバイスをサポートする必要がある場合でも、クライアント コードを変更せずにそれらを追加できます。

                   GPS <--Serial--> Server <--WCF--> Clients

私は何百もの異なるデバイスと通信するシステムを持っており、その多くはシリアル ポートやその他の信頼性の低い接続を介しており、これが私が使用するアプローチです。http://blog.abodit.comを参照してください。

----- TELNET を使用するための追加要件ごとに: おそらく次のようなもの:

デバイス自体とのすべての通信を処理するスレッドを作成します。

単一の WorkItem (送信対象、応答、および WaitHandle) をカプセル化するクラスを作成します。

Queue を使用して、クライアントからの要求をキューに入れます。各クライアントは、WaitHandle で応答の準備ができるまで待機します。

単一の通信スレッドがそのキューから作業項目を取得し、それらを GPS デバイスに送信し、応答を取得し、応答を WorkItem に保存 (または失敗のフラグを設定) し、待機ハンドルを設定して WorkItem が終わり。

要求が GPS の処理能力を超える速さで着信する場合は、コードを追加して、最後に成功した要求からデバイスへの短い時間枠内に着信した要求に対してキャッシュされた値を返すことができるようにします。

実際には、仮想 GPS デバイスをすべてのクライアントに提示していますが、内部的にはすべての要求を (キューで) シリアル化し、単一のスレッドで GPS デバイスとの通信を管理しているため、要求と応答のサイクルを干渉することなく簡単に実行できます。 .

これにより、適切に (待機ハンドルで) タイムアウトして、現在応答がないことをクライアントに通知することもできます。

于 2010-04-07T07:21:34.747 に答える
0

あなたはsocatとser2netと他のプログラムを持っていますが、私の経験は非常に悪いです...正しく動作していません. 私はこの小さな python プログラムを実行しましたが、役に立つ可能性があります。ポート、ボーレートを更新してから、任意の tcp クライアントを使用します。自動実行スクリプトとして使用したくない場合は、最初の行を削除します

#!/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()
于 2020-10-16T18:53:49.570 に答える