开发者

Mind boggling problem regarding RCON Protocol implementation in C#

开发者 https://www.devze.com 2023-03-02 17:49 出处:网络
I once again need your help figuring out this problem of mine...Been already a day and I can\'t seem to find out why this is happening in my code and output.

I once again need your help figuring out this problem of mine...Been already a day and I can't seem to find out why this is happening in my code and output.

Ok.....so basically I am trying to implement the RCON Protocol of Valve in C#, so far I am getting the expected output given the code and sample usage below:

Usage:

RconExec(socket, "cvarlist");

Code:

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 = pack开发者_高级运维et.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 "";
}

The Problem:

This is not yet the final code as I am just testing the output in the Debug window. There are a couple of issues occuring if I modify the code to it's actual state.

  1. Removing Thread.Sleep(50)

    • If I remove Thread.Sleep(50), the output doesn't complete and ends up throwing an exception. I noticed the 'END' termination string is sent by the server pre-maturely. This string was expected to be sent by the server only when the whole list completes.

      Mind boggling problem regarding RCON Protocol implementation in C#

      I tested this numerous times and same thing happens, if I don't remove the line, the list completes and function exits the loop properly.
  2. Removing Debug.WriteLine(response); within the loop and outputting the string using Debug.WriteLine(cmdResponse.ToString()); outside the loop, only partial list data is displayed. If I compare the actual bytes read from the loop with the length of the StringBuilder instance, they're just the same? Click here for the output generated.

Why is this happening given the two scenarios mentioned above?


You are not considering that Socket.Receive very well could read fewer bytes than the length of the supplied buffer. The return value tells you the number of bytes that was actually read. I see that you are properly storing this value in a variable, but I cannot see any code that use it.

You should be prepared to make several calls to Receive to retrieve the entire package. In particular when you receive the package data.

I'm not sure that this is the reason for your problem. But it could be, since a short delay on the client side could be enough to fill the network buffers so that the entire package is read in a single call.

Try using the following code to retrieve package data:

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

Note: You should also support the case when the first call to Receive (the one where you receive the package's data length) doesn't return 4 bytes.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号