Многопоточный сокет-сервер - получение данных - PullRequest
0 голосов
/ 17 февраля 2012

У меня есть простой TCP-сервер, который использует асинхронные сокеты. Проблема, с которой я сталкиваюсь, такова:

У меня есть следующий класс TCP-сервера:

 public class tcp_server {
         const int max_clients = 300;
         const int max_buffer_size = 10;

         public AsyncCallback pfnWorkerCallBack;
         private Socket m_mainSocket;
         private Socket[] m_workerSocket = new Socket[max_clients];
         private int m_clientCount = 0;

          ... 

         public void OnClientConnect(IAsyncResult asyn) { }
         public void WaitForData(System.Net.Sockets.Socket soc, int socket_id) { }
         public void OnDataReceived(IAsyncResult asyn)

         public class SocketPacket
         {
            public System.Net.Sockets.Socket m_currentSocket;
            public byte[] dataBuffer = new byte[max_buffer_size];
            public int socket_id = -1;
         }
}

Вот полный код функции OnDataRectained:

    public void OnDataReceived(IAsyncResult asyn)
    {
        try
        {
            SocketPacket socketData = (SocketPacket)asyn.AsyncState; // cast

            int iRx = 0;
            iRx = socketData.m_currentSocket.EndReceive(asyn);

            char[] chars = new char[iRx + 1];
            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);

            WaitForData(socketData.m_currentSocket, socketData.socket_id);
        }
        catch (ObjectDisposedException)
        {
            log("OnDataReceived: Socket has been closed\n");
        }
        catch (SocketException se)
        {
            log(se.Message);
        }
    }

max_buffer_size установлен на 10. Если я отправлю 100 байт на сервер, onDataRecieve будет выполнен 10 раз.

У меня 3 проблемы:

1 Мне нужно «собрать» все 100 байтов и затем передать их другой функции, которая будет проверять команды в полученных данных. Клиент добавляет 4-байтовый «идентификатор конца пакета» в конец пакета, потому что размер данных не всегда известен заранее. Как / где я могу определить этот временный буфер, чтобы onDataRecieve заполнил его, если найден конец, передаст данные в функцию идентификации команды?

2 Клиент может отправить мне много данных из разных потоков (по одному соединению). Мне нужен способ иметь несколько временных буферов для каждого полученного пакета, поэтому я могу подождать, пока они не заполнятся и не передадут буфер в зависимости от того, что будет заполнено в первую очередь для функции идентификации команды, а затем для очистки / удаления буфера.

Например:

  1. Клиент (Thread / Packet # 1) -> Сервер (неполные данные, поток по какой-то причине зависает)
  2. Клиент (Thread / Packet # 2) -> Сервер (полные данные, буфер передается функции id команды)
  3. Клиент (Thread / Packet # 1) -> Сервер (остальные данные для 1-го пакета поступают, буфер передается команде id func)

3 Мне нужно иметь доступ к этому буферу извне (публично), чтобы я мог начать использовать этот буфер из другого класса, пока он заполняется.

Надеюсь, это имеет смысл. Как мне это сделать?

1 Ответ

0 голосов
/ 29 октября 2012
  1. Я считаю, что необходимо либо находиться в OnDataReceived, либо вызывать другой класс через делегат или ссылку на другой класс или интерфейс. Если вы вызываете другой класс, то функция обратного вызова должна принимать только что полученные байты и обрабатывать их. Здесь важна любая необходимая синхронизация между потоками, поэтому я думаю, что она должна выполняться из OnDataReceived. Также я замечаю, что вы декодируете символы во время каждого вызова OnDataReceived. Это, вероятно, лучше всего делать, когда у вас есть полный пакет, если только вы точно никогда не отправляете однобайтовые символы (ASCII), в противном случае вы можете попытаться декодировать символ, который был разделен между отправками.

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

  3. Это хорошее место для очереди блокировки. Это версия CLR: http://msdn.microsoft.com/en-us/library/dd267312.aspx. Вы хотели бы использовать ее с параллельной очередью, http://msdn.microsoft.com/en-us/library/dd267265.aspx. Класс tcp_server поместит пакет в очередь после его полного получения, а затем другой поток (ы) может блокировать чтение из очереди и обрабатывать любые пакеты, помещенные в очередь.

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