Клиент асинхронного сокета получает

Я занимаюсь программированием сокетов на C #. Мне нужно создать клиентское приложение, которое взаимодействует с сервером с заданным протоколом.

Я успешно реализовал асинхронный метод отправки, но у меня проблемы с реализацией алгоритма приема. Метод синхронного приема работает нормально.

Прежде всего, мне нужно постоянно читать входящие сообщения и подтверждать их. Чтобы быть правильным, каждое полученное сообщение должно иметь терминатор (0x0c)

Я создал многопоточный класс под названием MessageFlow с тремя потоками: один отвечает за отправку сообщений, другой - за получение сообщений, третий - за интерпретацию полученных сообщений и выполнение каких-либо действий.

Рабочая функция для принимающего потока выглядит так

private void ReadSocketWorker()
{
    while (this.canRun)
    {
    xComClient.Receive();
    xComClient.receiveDone.WaitOne();
    Thread.Sleep(10);
    }
}

XComClient - это мой класс, имеющий сокет и все методы для отправки и получения сообщений.

public void Receive()
{
    try
    {
        StateObject state = new StateObject();
        state.workSocket = socketClient;
        socketClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
    }
    catch (Exception e)
    {
        throw e;
    }
}

private void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;

                // Read data from the remote device.
                int iReadBytes = client.EndReceive(ar);

                if (iReadBytes > state.GetBufferSize())
                {
                    byte[] bytesReceived = new byte[iReadBytes];
                    Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes);
                    state.responseList.Enqueue(bytesReceived);
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                        new AsyncCallback(ReceiveCallback), state);
                }
                else
                {
                    byte[] bytesReceived = new byte[iReadBytes];
                    Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes);
                    state.responseList.Enqueue(bytesReceived);
                    BuildReceivedMessage(state);
                    receiveDone.Set();
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

public class StateObject
{
    public Socket workSocket = null;
    public const int BufferSize = 20480;
    public byte[] buffer = new byte[BufferSize];

    public Queue<byte[]> responseList = new Queue<byte[]>();

    public int GetBufferSize()
    {
        return BufferSize;
    }
}

Что я делаю неправильно?


person Francesco    schedule 06.03.2012    source источник


Ответы (2)


Ваш дизайн представляет собой гибрид синхронного и асинхронного программирования. Правильно спроектированные асинхронные классы вообще не должны использовать какие-либо потоки, но позволяют .NET управлять потоками.

Очень надеюсь, что throw e; есть только в примере. Поскольку он уничтожает трассировку стека (и, следовательно, скрывает, где возникло исключение). Вы можете прочитать мою статью Не ловить это исключение и другие мои статьи с тегами исключений

Метод получения может выглядеть так:

void OnReceive(IAsyncResult ar)
{
    AppendInternalReadBuffer();
    CheckInternalReadBufferForMessageAndProcessIt();
    ReadAgain();
}

Это заблокирует сервер от обработки более одного сообщения за раз для каждого клиента. Если вы не хотите этого делать (что усложняет задачу), вы можете просто использовать ThreadPool в CheckInternalReadBufferForMessageAndProcessIt.

person jgauffin    schedule 06.03.2012
comment
Спасибо. Я напортачил, комбинируя синхронный / асинхронный подход - person Francesco; 06.03.2012

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

person user207421    schedule 06.03.2012