c # асинхронные сокеты, чтение всего буфера - PullRequest
0 голосов
/ 21 февраля 2012

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

Пакет использует следующий формат: PACKET_ID CONTENT END_OF_PACKET_INDICATOR

У меня есть следующая функция onDataRectained:

    public void OnDataReceived(IAsyncResult asyn)
    {

            SocketPacket socketData = (SocketPacket)asyn.AsyncState; 

            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);


            MessageBox.Show("Incoming data: " + socketData.dataBuffer.Length.ToString() + " from socket(" + socketData.socket_id + ")");

            char[] PACKET_END_IDENTIFIER = { (char)2, (char)1, (char)2, (char)1 };

            for (int i = 0; i < iRx; i++)
            {

                GLOBAL_BUFFER.Add(chars[iRx]);
            }

            if (PacketEndReached(chars, PACKET_END_IDENTIFIER))
            {
                // done reading the data
                PROCESS_PACKET(GLOBAL_BUFFER);
            }

            WaitForData(socketData.m_currentSocket, socketData.socket_id);
    }

Мой размер буфера сокета установлен на 100. Если я отправлю 1000 байтов, они будут разделены на 10 частей, а onDataRectained будет запущено 10 раз.

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

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

Спасибо!

ОБНОВЛЕНИЕ:

Это мой текущий класс:

public partial class TCP_SERVER
{
    const int MAX_CLIENTS = 3000;
    const int MAX_SOCKET_BUFFER_SIZE = 10;

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

    public GLOBAL_BUFFER; 

    public void StartServer(int listen_port)

    public void OnClientConnect(IAsyncResult asyn)

    public void ProcessIncomingData(char[] INCOMING_DATA, int CLIENT_ID)

    public void OnDataReceived(IAsyncResult asyn)
}

Как видите, GLOBAL_BUFFER определен «глобально».Если клиент отправляет пакет_1, для отправки которого требуется 10 секунд, и в то же время пакет_2, который для отправки данных занимает 2 секунды, будет перепутан.Мне нужно собрать данные для каждого пакета в отдельности .

Ответы [ 2 ]

0 голосов
/ 21 февраля 2012

Если это вообще возможно, я бы рекомендовал разрешить каждому клиентскому потоку иметь свое собственное подключение к серверу. Это поможет стеку Winsock дифференцировать сообщения от каждого потока и избежать любых потоков пакетов между сообщениями. Это позволит вам эффективно использовать способность стека расшифровывать, какие сообщения (и сегменты сообщений) должны быть сгруппированы вместе, прежде чем передавать их в ваше приложение как сообщение complete .

Дизайн сообщения, который вы описываете в то время как очень примитивный, может работать (надежно), только если вы разделяете свои потоки на разные соединения (или иным образом гарантируете, что за один раз клиент будет отправлять только одно сообщение). Вы применяете очень примитивную технику фрейма сообщения к вашему общению, которая поможет вам в определении границ сообщения, но причина его сбоя в том, что socketData.m_currentSocket.EndReceive(asyn); сообщит вам только количество байтов, полученных при событии. увеличивается (не обязательно общее количество байтов в сообщении). Вместо того, чтобы полагаться на него, чтобы узнать, сколько байтов было прочитано, я бы посоветовал читать входящее сообщение постепенно из цикла в вашем асинхронном обработчике, читая очень маленькие сегменты сообщения, пока он не обнаружит вашу последовательность байтов в конце сообщения. Это сообщит вашему событию, когда следует прекратить чтение и передать данные чему-то другому для их обработки.

Обычно я подхожу к кадрированию сообщений, имея до сообщения eye-catcher (некоторое значение, которое редко, если вообще когда-либо будет видно в сообщении), за которым следует длина сообщения (закодировано по вкусу, я лично использую двоичное кодирование для его эффективности), содержание сообщения и, наконец, секундный очар в конце вашего сообщения. Привлекающие внимание глаза служат в качестве логических очередей для разрывов сообщений в протоколе, а длина сообщения явно сообщает вашему серверу, сколько байтов ждать. Делая это таким образом, вы гарантированно получите необходимое количество байтов (если это не так, это проблема, поэтому отбросьте и / или выбросьте исключение), и это обеспечивает очень четкую границу между сообщениями, в которые вы можете кодировать, что позволяет прерывистая выборочная проверка и проверка.

0 голосов
/ 21 февраля 2012

Просто используйте Dictionary<String,List<Char>>, чтобы заменить текущие GLOBAL_BUFFER,

для хранения различных данных PACKET_ID в другой список.

Я настоятельно рекомендую вам идеальную платформу Socket Framework SuperSocket вам не нужно писать код для сокетов, это значительно повысит эффективность вашей разработки.

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