【问题标题】:C# TCP server receives two messages send by Python client at onceC# TCP 服务器同时接收 Python 客户端发送的两条消息
【发布时间】:2019-08-05 16:17:25
【问题描述】:

我正在尝试接收由 Python TCP 客户端发送到 C# 服务器的多条消息。 我确实收到了数据,但一次都收到了,我不希望这种情况发生。 我试图将服务器缓冲区大小设置为我发送的字节 [] 的大小,但它不起作用 (source)。 有什么想法可以解决这个问题吗?

客户端发送代码:

import socket


def send_to_remote(sock, data):

data_bytes = bytearray()
data_bytes.extend(map(ord, data)) # appending the array with string converted to bytes

bytes_length = len(data_bytes) # length of the array that I am sending

sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, bytes_length) #   setting the buffer size to the array length

print(bytes_length)

sock.send(data_bytes) # sending the data

服务器接收代码:

 public static string ReadData(TcpClient connection)
    {
        StringBuilder receivedDataStr = new StringBuilder();
        NetworkStream connectionStream = connection.GetStream();

        if (connectionStream.CanRead)
        {
            byte[] connectionBuffer = new byte[connection.ReceiveBufferSize];

            Console.WriteLine(">> Reading from NODE");

            int bytesRead = 0;

            bytesRead = connectionStream.Read(connectionBuffer, 0, 1024);
            receivedDataStr.Append(Encoding.ASCII.GetString(connectionBuffer, 0, bytesRead));

            Console.WriteLine(">> " + connection.ReceiveBufferSize);

            return receivedDataStr.ToString();
        }
        else
        {
            Console.WriteLine(">> Can't read from network stream");
            return "none-read";
        }
    }

编辑:

我做的是:

send_to_remote(socekt, "msg1")
send_to_remote(socekt, "msg1")

然后:

string msg1 = ReadData(client);
string msg2 = ReadData(client);

我收到 106200 的缓冲区数组。

结果是:

"msg1 (then new line) msg2"
"" (string msg2 is waiting for data)

提前谢谢你!!

【问题讨论】:

  • 编辑只是证实了我所说的一切...... 您的代码需要查找 CR/LF 并拆分消息并处理尚未完成的积压工作有效载荷(或者,正如我所说:使用StreamReader 为你做这件事)

标签: c# python .net sockets tcp


【解决方案1】:

TCP 是 stream 协议,而不是 packet 协议。 绝对不能保证您将获得与发送时完全相同的数据块 - 唯一可以保证的是您将以正确的顺序(或失败)获得字节,或超时等)。您可以单独获取每个字节,或一次获取 14 条消息。或介于两者之间的任何内容,包括一次接收一半的消息,另一半接收另一半。在 unicode(等)的情况下,这也意味着单个字符可以拆分为多个接收。

任何基于 TCP 的多消息协议都需要包含某种框架,即让您知道每条单独消息的开始和结束位置的某种方式。由于您使用的是基于文本的协议,因此一个常见的选项是使用 CR、LF 或 CR+LF 分隔逻辑消息 - 然后您的工作就是缓冲数据,直到获得完整的消息 - 通过查找行结束。为了完整性:在二进制协议的情况下,通常使用某种标头为有效负载添加长度前缀,该标头指示有效负载中的数据量,然后您只需要解析标头,确定长度和缓冲,直到您有这么多数据。

在具有文本协议且没有具有挑战性的可扩展性问题的简单应用程序中,可以使用StreamReader(在NetworkStream 之上)为您完成该部分,然后只需使用ReadLine 或@987654325 @。但是请注意,这在“真实”服务器(尤其是ReadLine)中是个坏主意——您不希望恶意或错误的客户端永远锁定线程,因为它发送了几个字符而没有行结束,然后没有发送任何其他东西......曾经。当然,在一个严肃的服务器中,您不会为每个客户端使用一个线程无论如何

【讨论】:

  • @IvanZlatanov CR/LF 这里只是意味着:行尾-根据编辑似乎已经到位;然而,处理积压是很棘手的;如果你不确定你在这里做什么,再一次:我建议 StreamReaderReadLine 是你最好的选择(只是强调:不要对大容量服务器这样做 - 它有效,但这不是编写服务器的好方法 - 但是显示如何“正确”编写服务器需要很长时间)
  • 我认为我会真正使用 StreamReader,因为我还在学习,不想把一切都搞砸。我仍然感到困惑的一件事是巨大的缓冲区大小,这不是很糟糕而且很消耗内存吗?
  • @IvanZlatanov 几乎可以肯定是一个非常糟糕的主意,是的;但是:一旦你切换到NetworkStreamStreamReader你无论如何都不做阅读,所以你根本不需要那个缓冲区。 StreamReader 会替你担心的。
  • 这可能有点跑题了,但是你能推荐我一些关于该主题的文章甚至书籍吗(如何正确设计和编写服务器)?
  • @IvanZlatanov 确定;我谦虚地提出,对于 modern 代码,我自己的文章在这方面做得很好 - 特别是,part 3 here 显示了很多代码,尽管是在二进制协议上下文中 - 但想法是一样的。显然我会从第 1 部分开始......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-29
  • 2019-12-06
  • 2017-09-02
  • 1970-01-01
  • 2019-10-01
  • 2023-04-03
相关资源
最近更新 更多