[英]Retrieving entire line from a socket in C#?
我有一个简单的客户端-服务器系统发送纯文本-尽管只有已批准的命令。 该服务器是一个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"))
当您进行套接字编程时,请务必注意,数据可能不会一次全部可用。 实际上,这正是您所看到的。 您的邮件已被拆分。
那么,为什么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
的DataAvailable
属性返回true时,它就有数据。 但是,如前所述,不能保证该数据是什么。 它可能是一个字节。 或消息的一部分。 或完整的消息以及下一条消息的一部分。 请注意,根据编码的不同,甚至可能只接收一部分字符 。 并非所有字符编码都将所有字符最多为一个字节。 这包括cfg.GameSendConnection.sendall((action + "\\n").encode("utf-8"))
发送的UTF-8。
如何解决呢? 读取字节,而不是行。 将它们放在一些缓冲区中。 每次读取后,检查缓冲区是否包含换行符。 如果是这样,您现在将有一条完整的消息要处理。 从缓冲区中删除直到并包括换行符的消息,并继续向其添加新数据,直到接收到下一个换行符为止。 等等。
这就是我在相似的应用程序中处理整行的方式,这是一个非常简单的代码,您的代码可能有所不同,但是您可以理解。
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 = "";
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.