Поразительная проблема, связанная с реализацией протокола RCON в C # - PullRequest
4 голосов
/ 03 мая 2011

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

Хорошо ..... так что в основном я пытаюсь реализовать протокол RCON Valve в C #, до сих пор я получаю ожидаемый вывод , учитывая код и пример использования ниже:

Использование:

RconExec(socket, "cvarlist");

Код:

private string RconExec(Socket sock, string command)
{
    if (!sock.Connected) throw new Exception("Not connected");

    //sock.DontFragment = true;
    sock.ReceiveTimeout = 10000;
    sock.SendTimeout = 10000;
    //sock.Blocking = true;

    Debug.WriteLine("Executing RCON Command: " + command);

    byte[] rconCmdPacket = GetRconCmdPacket(command);
    sock.Send(rconCmdPacket); //Send the request packet
    sock.Send(GetRconCmdPacket("echo END")); //This is the last response to be received from the server to indicate the end of receiving process
    RconPacket rconCmdResponsePacket = null;

    string data = null;

    StringBuilder cmdResponse = new StringBuilder();

    RconPacket packet = null;
    int totalBytesRead = 0;

    do
    {
        byte[] buffer = new byte[4]; //Allocate buffer for the packet size field
        int bytesReceived = sock.Receive(buffer); //Read the first 4 bytes to determine the packet size
        int packetSize = BitConverter.ToInt32(buffer, 0); //Get the packet size

        //Now proceed with the rest of the data
        byte[] responseBuffer = new byte[packetSize];

        //Receive more data from server
        int bytesRead = sock.Receive(responseBuffer);

        //Parse the packet by wrapping under RconPacket class
        packet = new RconPacket(responseBuffer);
        totalBytesRead += packet.String1.Length;

        string response = packet.String1;
        cmdResponse.Append(packet.String1);

        Debug.WriteLine(response);

        Thread.Sleep(50);

    } while (!packet.String1.Substring(0,3).Equals("END"));

    Debug.WriteLine("DONE..Exited the Loop");
    Debug.WriteLine("Bytes Read: " + totalBytesRead + ", Buffer Length: " + cmdResponse.Length);

    sock.Disconnect(true);

    return "";
}

Проблема:

Это еще не окончательный код, так как я просто проверяю вывод в окне отладки.При изменении кода до его фактического состояния возникает пара проблем.

  1. Удаление Thread.Sleep(50)

    • Если я удаляю Thread.Sleep(50), вывод не завершается и в итоге выдает исключение.Я заметил, что строка завершения 'END' отправляется сервером преждевременно.Ожидается, что эта строка будет отправлена ​​сервером только после завершения всего списка.Exception Thrown Я проверял это много раз, и происходит то же самое, если я не удаляю строку, список завершается и функция правильно выходит из цикла.
  2. Удаление Debug.WriteLine(response); внутри цикла и вывод строки с использованием Debug.WriteLine(cmdResponse.ToString()); вне цикла, отображаются только частичные данные списка.Если я сравниваю фактические байты, прочитанные из цикла, с длиной экземпляра StringBuilder, они точно такие же?Нажмите здесь для сгенерированного вывода.

Почему это происходит с учетом двух вышеупомянутых сценариев?

1 Ответ

3 голосов
/ 04 мая 2011

Вы не считаете, что Socket.Receive очень хорошо может прочитать меньше байтов, чем длина предоставленного буфера. Возвращаемое значение сообщает вам количество байтов, которые были фактически прочитаны. Я вижу, что вы правильно храните это значение в переменной, но я не вижу ни одного кода, который его использует.

Вы должны быть готовы сделать несколько звонков на Receive, чтобы получить весь пакет. В частности, когда вы получаете данные пакета.

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

Попробуйте использовать следующий код для получения данных пакета:

int bufferPos = 0;
while (bufferPos < responseBuffer.Length)
{
    bufferPos += socket.Receive(responseBuffer, bufferPos, responseBuffer.Length - bufferPos, SocketFlags.None);
}

Примечание. Вам следует также поддерживать случай, когда первый вызов Receive (тот, где вы получаете длину данных пакета) не возвращает 4 байта.

...