Пытаетесь сделать код асинхронным, но без блокировки моя программа убегает? - PullRequest
0 голосов
/ 21 сентября 2011

При написании клиент-серверной программы и ранее использовались такие вызовы:

TcpListener.AcceptTcpClient() NetworkStream.Read() NetworkStream.Write()

TcpListener.AcceptTcpClient() работает нормально, потому что его функция обратного вызова тольковызывается после установления соединения.

Однако BeginRead() также не работает.По какой-то причине он выполняется и продолжается после него, даже если данные не отправляются. Не уверен, что происходит.NetworkStream.Read() блокировал просто отлично, но это не так.

Вот нерабочий поток, который создается при каждом установлении соединения:

private void HandleClientCommunication(object client)
{
    TcpClient tcpClient = (TcpClient)client;
    NetworkStream clientStream = tcpClient.GetStream();

    try
    {
        byte[] header = new byte[4];

        clientStream.BeginRead(header, 0, header.Length, Read, new StateData(clientStream, header)); // Runs even if no data is sent

        int dataLength = BitConverter.ToInt32(header, 0); // Continues to this, even if no packets are sent..

        byte[] data = new byte[dataLength]; // dataLength is 0 still of course because none of the code is blocking

        clientStream.BeginRead(data, 0, dataLength, Read, new StateData(clientStream, data));
    }
    catch (IOException e)
    {
        Console.WriteLine(e.InnerException.Message);
    }

    // not relevant past here
}

Вот и метод Read,Не уверен, если это необходимо, чтобы выяснить проблему, но я включу ее независимо от того:

private void Read(IAsyncResult async)
{
    StateData stateData = (StateData)async.AsyncState;

    stateData.BytesRead += stateData.Stream.EndRead(async);

    if (stateData.BytesRead < stateData.Bytes.Length)
    {
        stateData.Stream.BeginRead(stateData.Bytes, 0, stateData.Bytes.Length, Read, stateData);
    }
    else
    {
        string message = Encoding.ASCII.GetString(stateData.Bytes);

        Console.WriteLine(message);
    }
}

Так что да, я просто пытаюсь настроить взаимодействие клиент-сервер с асинхронными вызовами и иметь каждый «пакет»включите заголовок с длиной данных как int, а затем сразу после этого сами данные.К сожалению, кажется, что все не работает, и я не уверен, в чем проблема.

Похоже, мне нужно включить некоторую ручную форму блокировки, но разве это не противоречит цели использования асинхронных вызовов?Почему бы тогда просто не вернуться к обычным синхронным вызовам блокировки, таким как Read() и AcceptTcpClient() в этот момент?

Не думаю, что здесь я полностью понимаю вещи ..

1 Ответ

3 голосов
/ 21 сентября 2011

Однако BeginRead () также не работает.По какой-то причине он выполняется и продолжается после него, даже если данные не отправляются. Не уверен, что происходит.NetworkStream.Read () блокировал просто отлично, но это не так.

Я думаю, вы неправильно поняли, для чего предназначен BeginRead.Это не означает, что блокировать - он выполняет асинхронное чтение, выполняя заданный обратный вызов, когда чтение завершено.Это означало немедленный возврат - поэтому неудивительно, что ваши данные заголовка пусты.

По сути, любая работа, требующая данных, должна быть в обратном вызове, а не в том же методе, который вызывает BeginRead.Ваш первый обратный вызов должен преобразовать данные заголовка, а затем BeginRead снова с другим обратным вызовом, чтобы прочитать сами данные сообщения ... хотя вы должны также иметь в виду, что любой вызов Read / BeginReadможет не прочитать все данные, которые вы запрашивали.Вы пытаетесь учесть это в вашем обратном вызове, но вы не совсем там - потому что вы всегда пытаетесь заполнить буфер с самого начала - который перезапишет любойсуществующие данные.Если вы знаете, сколько данных вы ожидаете в целом, и ваш буфер такой длинный, вам следует прочитать в буфер , начиная с , сколько байтов вы уже прочитали.

Обратите внимание, что C #5 сделает все это намного проще - но если вы не можете ждать до тех пор, вам может быть проще вернуться к блокировке вызовов в нескольких потоках (по одному на клиента).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...