关于 C# 中 RCON 协议实现的令人难以置信的问题

发布于 2024-11-04 22:45:17 字数 2929 浏览 0 评论 0原文

我再次需要您的帮助来解决我的这个问题...已经一天了,我似乎无法找出为什么在我的代码和输出中发生这种情况。

好吧......所以基本上我正在尝试实现 Valve 的 RCON 协议在 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 实例的长度进行比较,它们是相同的吗?单击此处查看生成的输出。

鉴于上述两种情况,为什么会发生这种情况?

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 = 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 "";
}

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.
      Exception Thrown 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

恬淡成诗 2024-11-11 22:45:17

您没有考虑到 Socket.Receive 可以很好地读取比提供的缓冲区长度更少的字节。返回值告诉您实际读取的字节数。我发现您正确地将这个值存储在变量中,但我看不到任何使用它的代码。

您应该准备好多次调用 Receive 来检索整个包。特别是当您收到包裹数据时。

我不确定这就是你的问题的原因。但也有可能,因为客户端的短暂延迟可能足以填充网络缓冲区,以便在一次调用中读取整个包。

尝试使用以下代码检索包数据:

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

注意:您还应该支持第一次调用 Receive(您接收包数据长度的调用)不返回 4 个字节的情况。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文