我再一次需要你的帮助来解决我的这个问题......已经有一天了,我似乎无法找出为什么在我的代码和输出中发生这种情况。
好的.....所以基本上我正在尝试在C#中实现Valve的RCON Protocol,到目前为止,我得到expected output给出下面的代码和示例用法:
用法:
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 "";
}
问题:
这还不是最终的代码,因为我只是在Debug窗口中测试输出。如果我将代码修改为实际状态,则会出现一些问题。
删除Thread.Sleep(50)
Thread.Sleep(50)
,则输出无法完成并最终抛出异常。我注意到'END'终止字符串是由服务器提前发送的。只有当整个列表完成时,才会由服务器发送此字符串。
我测试了这么多次,同样的事情发生了,如果我不删除该行,列表完成并且函数正确地退出循环。 在循环中删除Debug.WriteLine(response);
并在循环外使用Debug.WriteLine(cmdResponse.ToString());
输出字符串,仅显示部分列表数据。如果我将从循环读取的实际字节数与StringBuilder实例的长度进行比较,它们是否相同?单击here以获取生成的输出。
鉴于上述两种情况,为什么会发生这种情况?
答案 0 :(得分:3)
您并没有考虑Socket.Receive
读取的字节数少于提供的缓冲区长度。返回值告诉您实际读取的字节数。我看到你正确地将这个值存储在变量中,但我看不到任何使用它的代码。
您应该准备好多次调用Receive
来检索整个包。特别是当您收到包裹数据时。
我不确定这是你问题的原因。但它可能是,因为客户端的短暂延迟可能足以填满网络缓冲区,以便在一次调用中读取整个包。
尝试使用以下代码检索包数据:
int bufferPos = 0;
while (bufferPos < responseBuffer.Length)
{
bufferPos += socket.Receive(responseBuffer, bufferPos, responseBuffer.Length - bufferPos, SocketFlags.None);
}
注意:当第一次调用Receive
(您收到数据包的数据长度的那个)没有返回4个字节时,您也应该支持这种情况。