我有一个简单的客户端 - 服务器系统发送纯文本 - 尽管只有已经批准的命令。服务器是一个Python系统 - 我已经确认了正确的连接。
然而,客户端是C# - 在Unity中。在搜索示例时,我偶然发现了这段代码。它确实似乎做了我想要的,但只是部分:
public String readSocket()
{
if (!socketReady)
return "";
if (theStream.DataAvailable)
return theReader.ReadLine();
return "";
}
我发送的字符串以\ n结束,但我只得到这样的消息的一半:
消息A:
消息B:
_20_case
claim_1
我知道这可能与我如何直接阅读该行有关,但我找不到更好的例子 - 奇怪的是,即使有多个人指出问题,每个人似乎都会回到这个片段。
可以做些什么来正确修复这段代码吗?
如果有帮助,我会发送信息(来自我的Python服务器):
action = str(command) + "_" + str(x) + "_" + str(userid) + "_" + str(user)
cfg.GameSendConnection.sendall((action + "\n").encode("utf-8"))
答案 0 :(得分:0)
当你进行套接字编程时,重要的是要注意数据可能不是 一体式提供。事实上,这正是你所看到的。您的 消息正在被打破。
那么为什么ReadLine
不要等到有一行要读?
以下是一些简单的示例代码:
var stream = new MemoryStream();
var reader = new StreamReader(stream);
var writer = new StreamWriter(stream) { AutoFlush = true };
writer.Write("foo");
stream.Seek(0, SeekOrigin.Begin);
Console.WriteLine(reader.ReadLine());
请注意,最后没有换行符。不过,这个输出很少
代码段为foo
。
ReadLine
将字符串返回到第一个换行符或直到没有
更多要读取的数据。从没有更多数据的流中读取异常
要读取的数据,然后返回null
。
当NetworkStream
的{{1}}属性返回true时,它有
数据。但如前所述,无法保证这一点
数据是。它可能是一个字节。或者是消息的一部分。或者完整的消息
加上下一条消息的一部分。请注意,根据编码,它可以
甚至可以只接收角色的一部分。不是所有角色
编码的所有字符最多只能是一个字节。这包括DataAvailable
发送的UTF-8。
如何解决这个问题?读取字节,而不是行。把它们放在缓冲区里。每一次之后 读取,检查缓冲区是否包含换行符。如果是的话,你现在已经满了 要处理的消息。从中移除消息,包括换行符 缓冲并继续向其追加新数据,直到收到下一个换行符。和 等等。
答案 1 :(得分:0)
这就是我在类似应用程序中处理整行的方法,这是一个非常简单的代码,你的代码可能不同,但你可以理解。
private string incompleteRecord = "";
public void ReadSocket()
{
if (_networkStream.DataAvailable)
{
var buffer = new byte[8192];
var receivedString = new StringBuilder();
do
{
int numberOfBytesRead = _networkStream.Read(buffer, 0, buffer.Length);
receivedString.AppendFormat("{0}", Encoding.UTF8.GetString(buffer, 0, numberOfBytesRead));
} while (_networkStream.DataAvailable);
var bulkMsg = receivedString.ToString();
// When you receive data from the socket, you can receive any number of messages at a time
// with no guarantee that the last message you receive will be complete.
// You can receive only part of a complete message, with next part coming
// with the next call. So, we need to save any partial messages and add
// them to the beginning of the data next time.
bulkMsg = incompleteRecord + bulkMsg;
// clear incomplete record so it doesn't get processed next time too.
incompleteRecord = "";
// loop though the data breaking it apart into lines by delimiter ("\n")
while (bulkMsg.Length > 0)
{
var newLinePos = bulkMsg.IndexOf("\n");
if (newLinePos > 0)
{
var line = bulkMsg.Substring(0, newLinePos);
// Do whatever you want with your line here ...
// ProcessYourLine(line)
// Move to the next message.
bulkMsg = bulkMsg.Substring(line.Length + 1);
}
else
{
// there are no more newline delimiters
// so we save the rest of the message (if any) for processing with the next batch of received data.
incompleteRecord = bulkMsg;
bulkMsg = "";
}
}
}
}