繁体   English   中英

从C#中的套接字检索整行?

[英]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:

  1. Claim_2

讯息B:

  1. _20_case

  2. 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

NetworkStreamDataAvailable属性返回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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM