Совместное использование COM-порта через TCP - PullRequest
1 голос
/ 07 апреля 2010

Какой будет простой шаблон проектирования для совместного использования COM-порта по TCP для нескольких клиентов?

Например, локальное устройство 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 и потоками.

I 'Я не уверен, что приведенный выше код является лучшим способом продвижения вперед, поэтому у кого-нибудь есть другое решение (чем проще, тем лучше)?

1 Ответ

2 голосов
/ 07 апреля 2010

Зачем писать на таком низком уровне (сокеты)? Почему бы не использовать WCF в качестве связи между клиентами и сервером и представить более чистый, строго типизированный интерфейс вместо простого доступа к устройству GPS?

Устройства, подобные этому, часто лучше всего управляются независимо от звонящих клиентов, т. Е. У вас есть собственный отдельный поток, который общается с устройством GPS, опрашивает его с соответствующим интервалом и заполняет общие структуры данных текущим местоположением, в то время как клиенты совершать сервисные вызовы и снабжаются данными из общих структур данных. Вся обработка ошибок и восстановление для иногда ненадежного соединения с устройством обрабатывается потоком GPS, и клиентам не нужно вмешиваться в такую ​​злобу. Они могут совершать неблокирующие вызовы для получения обновлений статуса, и эти обновления могут включать статус «позиция недоступна», пока поток GPS отчаянно пытается восстановить связь.

Итак, я бы создал сервис, который абстрагирует особенности работы с этим конкретным устройством и предоставляет чистый интерфейс для клиентов. Например, он может предлагать такие сервисы, как GetPosition (), который возвращает некоторый класс, такой как «GeoCoordinate». Таким образом, если вам когда-либо потребуется поддержка других устройств определения местоположения, вы можете добавить их, не внося никаких изменений в код клиента.

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

У меня есть система, которая обменивается данными с сотнями различных устройств, многими через последовательные порты и другие полунадежные соединения, и этот подход я использую. Смотри http://blog.abodit.com.

----- согласно вашему дополнительному требованию использовать TELNET: может быть что-то вроде:

Создать поток, который обрабатывает все коммуникации с самим устройством.

Создайте класс, который инкапсулирует один WorkItem - что отправлять, ответ и WaitHandle.

Использование очереди для постановки в очередь запросов от клиентов. Каждый клиент ждет в WaitHandle, чтобы его ответ был готов.

Позвольте единственному потоку связи извлечь рабочие элементы из этой очереди, отправить их на устройство GPS, получить ответ, сохранить ответ в WorkItem (или установить флаг для сбоев), а затем установить дескриптор ожидания, чтобы сказать, что WorkItem завершен.

Если запросы поступают быстрее, чем может обработать GPS, добавьте код, чтобы он мог возвращать кэшированные значения для запросов, поступающих в течение небольшого временного интервала с момента последнего успешного запроса на устройство.

Фактически вы теперь предоставляете виртуальное устройство GPS всем клиентам, но внутри вы сериализуете все их запросы (в очереди) и управляете связью с устройством GPS в одном потоке, чтобы вы могли выполнить цикл запрос-ответ легко без помех.

Это также позволяет вам тайм-аут (на дескриптор ожидания), чтобы сообщить клиенту, что в настоящее время нет ответа.

...