关于 C# 中 RCON 协议实现的令人难以置信的问题
我再次需要您的帮助来解决我的这个问题...已经一天了,我似乎无法找出为什么在我的代码和输出中发生这种情况。
好吧......所以基本上我正在尝试实现 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 "";
}
问题:
这还不是最终代码,因为我只是在调试窗口中测试输出。如果我将代码修改为实际状态,则会出现一些问题。
删除
Thread.Sleep(50)
- 如果我删除
Thread.Sleep(50)
,输出将无法完成并最终引发异常。我注意到服务器过早地发送了“END”终止字符串。仅当整个列表完成时,服务器才会发送该字符串。 我对此进行了多次测试,并且会发生同样的事情,如果我不删除该行,列表就会完成并运行正确退出循环。
- 如果我删除
在循环内删除
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.
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.
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.
- If I remove
Removing
Debug.WriteLine(response);
within the loop and outputting the string usingDebug.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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您没有考虑到
Socket.Receive
可以很好地读取比提供的缓冲区长度更少的字节。返回值告诉您实际读取的字节数。我发现您正确地将这个值存储在变量中,但我看不到任何使用它的代码。您应该准备好多次调用
Receive
来检索整个包。特别是当您收到包裹数据时。我不确定这就是你的问题的原因。但也有可能,因为客户端的短暂延迟可能足以填充网络缓冲区,以便在一次调用中读取整个包。
尝试使用以下代码检索包数据:
注意:您还应该支持第一次调用
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:
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.