C # / .NET Держите именованный канал открытым и поддерживайте любое количество параллельных подключающихся клиентов. - PullRequest
5 голосов
/ 14 марта 2019

У нас есть несколько клиентов, которые подключаются к серверу по именованным каналам. Иногда мы видим ошибку pipe/file not found, когда клиент пытается подключиться к именованному каналу. Наш оригинальный код

    while (!cancelToken.IsCancellationRequested)
    {
        // This creates a new NamedPipeServerStream
        var stream = PipeHelper.NewCurrentUserServerStream(PipeNames.Server, PipeTransmissionMode.Byte);
        await stream.WaitForConnectionAsync(cancelToken);

        Task.Run(() => HandleStreamAsync(stream).WithExceptionTrapper(LogNamedPipeException));

Из того, что я могу сказать, следует создать NamedPipeServerStream и затем вызвать WaitForConnection, тогда сервер должен обработать запрос.

Однако, если этот запрос близок к мгновенному, или клиент закрывает канал, представляется вероятным, что поток сервера будет закрыт, а весь именованный канал исчезнет, ​​прежде чем код зацикливается и создается новый поток сервера. .

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

Код здесь https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-use-named-pipes-for-network-interprocess-communication предполагает, что просто использовать несколько потоков - вариант (4, в этом примере). Однако, похоже, это только уменьшает вероятность ошибки, и клиент может попытаться подключиться в редком промежутке, когда все 4 потока только что закрыли поток сервера, и именованный канал исчезает. Кроме того, он ограничивает параллельное выполнение до 4 потоков.

Существует ли механизм, позволяющий нам открывать именованный сервер каналов, который допускает произвольное количество соединений, создает новый поток сервера для каждого соединения и никогда не рискует закрыть именованный канал?

Прямо сейчас мы думаем сделать это:

    var nextStream = PipeHelper.NewCurrentUserServerStream(PipeNames.Server, PipeTransmissionMode.Byte);
    while (!cancelToken.IsCancellationRequested)
    {
        try
        {
            await nextStream.WaitForConnectionAsync(cancelToken);
            var currentStream = nextStream;
            // Always have another stream ready so if the task is handled and finished 
            // really quickly theres no chance of the named pipe being removed altogether.
            nextStream = PipeHelper.NewCurrentUserServerStream(PipeNames.Server, PipeTransmissionMode.Byte);

            Task.Run(() => HandleStreamAsync(currentStream).WithExceptionTrapper(LogNamedPipeException));
        }

Это в основном гарантирует, что мы создадим второй поток сервера, прежде чем мы начнем обрабатывать соединение с первым потоком сервера, поэтому мы гарантируем, что всегда есть один активный, и мы запускаем обработчик для отдельной задачи, поэтому мы должны запустить другой WaitForConnection как можно скорее.

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

1 Ответ

1 голос
/ 14 марта 2019

Итак, как мы можем гарантировать, что именованный канал всегда существует независимо от времени и количества подключающихся клиентов?

Это невозможно для любого типа сетевого сервера. Даже TCP / IP (на котором построены именованные каналы) имеет ограниченное «отставание». Даже если вы измените количество невыполненных заданий, вы все равно будете ограничены серверным оборудованием.

То, что вы можете сделать, - это всегда поддерживать определенное количество вызовов прослушивания (т. Е. WaitForConnectionAsync), поэтому у вас всегда будет большое количество слушателей, которые будут работать постоянно, начиная новое прослушивание, как только как каждый завершает, так же, как ваш последний пример кода. Вы захотите запустить этот код несколько раз, например, около 20, чтобы у вас было много слушателей. Все, что вы можете сделать, это минимизировать вероятность пропуска соединения; Вы не можете предотвратить это полностью.

...