Именованные каналы: как серверная сторона может узнать, что клиент отключился? - PullRequest
2 голосов
/ 01 февраля 2012

У меня есть 2 приложения, использующие именованные каналы.

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

У меня не было проблем с реализацией первой части (отправка сообщений с сервера на клиент) с использованием сервера с PipeDirection.Out и клиента с PipeDirection.In. Но когда я попытался изменить код так, чтобы сервер и клиент оба имели PipeDirection.InOut (чтобы можно было отправлять сообщения от клиента к серверу), код перестал работать. Программа зависает, когда я делаю writer.Flush (на стороне сервера) или writer.WriteByte (на стороне клиента). Места, в которых он висит, помечены как [ЗДЕСЬ ВЕДУЩИ].

Сервер создан так:

public static void CreatePipeServerStream()    
{
    var namedPipeServerStream = new NamedPipeServerStream("somename", PipeDirection.InOut);
    namedPipeServerStream.WaitForConnection();

    // This thread is wating for message from client
    ThreadStart starter = () => WaitForSignalFromClient(namedPipeServerStream);
    new Thread(starter).Start();
}

private static void WaitForSignalFromClient(NamedPipeServerStream namedPipeServerStream)
{
    if (namedPipeServerStream.IsConnected)
    {
        namedPipeServerStream.ReadByte();
        // we'll get here after something is read
        // and if we got here, we should close the server pipe
        // now I can get here only if I shut down the client program using Task manager
        namedPipeServerStream.Close();
    }
}

Процедура отправки сообщения клиенту делает это (используется для работы, когда у сервера было направление трубы == Out, а у клиента было направление трубы == In):

public static void SendMessageUsingPipe(NamedPipeServerStream namedPipeServerStream)
{
    if (namedPipeServerStream.IsConnected)
    {
        var sw = new StreamWriter(namedPipeServerStream);
        sw.WriteLine("smth");
        // [HANGS HERE]
        sw.Flush();
    }
}

На стороне клиента этот код выполняется в отдельном потоке:

private void WaitServerCommands()
{
    _pipe = new NamedPipeClientStream(".", "somename", PipeDirection.InOut);
    using (var rdr = new StreamReader(_pipe))
    {
        while (true)
        {
            if (!_pipe.IsConnected)
            {
                _pipe.Connect();
            }
            rdr.ReadLine();
            // I don't care what was sent by server, I just need to know that something was sent
            Invoke(_handleCommand);
        }
    }
}

Код, который должен отправить сообщение на сервер:

private void ClosePipes()
{
    if (_pipe != null && _pipe.IsConnected)
    {
        // [HANGS HERE]
        _pipe.WriteByte(113);
        _pipe.WaitForPipeDrain();
        _pipe.Close();
    }
}

Есть идеи, что не так с кодом? Или, может быть, я что-то упустил фундаментальное?

Фактическая проблема заключается в том, что мне нужно знать на стороне сервера, что клиент отключился. Может быть, это может быть достигнуто другим способом?

1 Ответ

1 голос
/ 02 февраля 2012

Не думаю, что вы правильно настроили пипсервер.

namedPipeServerStream.WaitForConnection () будет блокировать текущий поток, пока клиент не подключится.

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

namedPipeServerStream.ReadByte();
rdr.ReadLine();

Я предполагаю, что они находятся в безвыходном положении, ожидая, пока один из них отправит некоторую информацию.

...