TcpClient.GetStream()。CopyTo(MemoryStream)阻止应用程序继续?

时间:2023-02-14 04:51:13

I'm trying to perform some extremely basic network operations, yet I'm having some trouble.

我正在尝试执行一些非常基本的网络操作,但我遇到了一些麻烦。

Originally, I was trying to use NetworkStream.Length to create a new byte[], but it became apparent that this is not possible since NetworkStream does not support seek operations.

最初,我试图使用NetworkStream.Length来创建一个新的byte [],但很明显这是不可能的,因为NetworkStream不支持搜索操作。

I then found some examples showing how to copy the NetworkStream to a MemoryStream, which allows seek operations. So far, so good.

然后我找到了一些示例,展示了如何将NetworkStream复制到MemoryStream,它允许搜索操作。到现在为止还挺好。

Or is it?

或者是吗?

Once the scope of the using statement gets hit, the application essentially stops. It's still running, doing something, but I can't really tell what. Here's the code:

一旦命中using语句的范围,应用程序就会停止。它还在运行,做某事,但我无法说出什么。这是代码:

    void HandleClientComm(object client)
    {
        TcpClient tcpClient = (TcpClient)client;

        //copy client stream to memory stream to allow seek operations
        MemoryStream clientStream = new MemoryStream();
        using (var clientRequestStream = tcpClient.GetStream())
        {
            clientRequestStream.CopyTo(clientStream);
        }

        //...
    }

So there's where my problem has me completely stumped. I need to copy my NetworkStream to a MemoryStream to do some processing, but this task alone is proving more difficult than it should be.

所以我的问题让我完全陷入困境。我需要将我的NetworkStream复制到MemoryStream来进行一些处理,但是这个任务本身就比它应该更难。

Has anybody encountered this issue before?

以前有人遇到过这个问题吗?

1 个解决方案

#1


3  

A TCP stream is often not terminated - i.e. the inbound stream is technically alive until the socket is broken (or at a minimum : the other end of the socket elects to close their outbound link, perhaps keeping their inbound link open to get the reply).

TCP流通常不会被终止 - 即入站流在技术上是活动的,直到套接字被破坏(或者至少:套接字的另一端选择关闭其出站链接,可能保持其入站链接打开以获得回复) 。

Now: CopyTo will want to read to the end of the stream. Of a stream that has no end. The behaviour of Read is:

现在:CopyTo将要读到流的末尾。没有尽头的流。 Read的行为是:

  • block until at least one byte is available...
  • 阻止,直到至少有一个字节可用...
  • or until the stream is closed...
  • 或直到流关闭...
  • or until a timeout
  • 或者直到超时

If timeouts aren't enabled, and the socket doesn't close ever, then: boom.

如果没有启用超时,并且套接字没有关闭,那么:繁荣。

For this reason, socket code usually needs to be very careful in terms of "framing" - i.e. knowing how much data to read as a unit. This is often done via some form length-prefix in the data stream, i.e. "the next message is 27 bytes" - then you know to only try to read 27 more bytes, because reading a 28th might block you forever. In text-based protocols, this is often done using sentinel values like line-feed.

出于这个原因,套接字代码在“成帧”方面通常需要非常小心 - 即知道要读取多少数据作为一个单元。这通常通过数据流中的某种形式长度前缀来完成,即“下一个消息是27个字节” - 然后你知道只尝试读取27个字节,因为读取第28个可能会永远阻止你。在基于文本的协议中,这通常使用像换行这样的标记值来完成。

#1


3  

A TCP stream is often not terminated - i.e. the inbound stream is technically alive until the socket is broken (or at a minimum : the other end of the socket elects to close their outbound link, perhaps keeping their inbound link open to get the reply).

TCP流通常不会被终止 - 即入站流在技术上是活动的,直到套接字被破坏(或者至少:套接字的另一端选择关闭其出站链接,可能保持其入站链接打开以获得回复) 。

Now: CopyTo will want to read to the end of the stream. Of a stream that has no end. The behaviour of Read is:

现在:CopyTo将要读到流的末尾。没有尽头的流。 Read的行为是:

  • block until at least one byte is available...
  • 阻止,直到至少有一个字节可用...
  • or until the stream is closed...
  • 或直到流关闭...
  • or until a timeout
  • 或者直到超时

If timeouts aren't enabled, and the socket doesn't close ever, then: boom.

如果没有启用超时,并且套接字没有关闭,那么:繁荣。

For this reason, socket code usually needs to be very careful in terms of "framing" - i.e. knowing how much data to read as a unit. This is often done via some form length-prefix in the data stream, i.e. "the next message is 27 bytes" - then you know to only try to read 27 more bytes, because reading a 28th might block you forever. In text-based protocols, this is often done using sentinel values like line-feed.

出于这个原因,套接字代码在“成帧”方面通常需要非常小心 - 即知道要读取多少数据作为一个单元。这通常通过数据流中的某种形式长度前缀来完成,即“下一个消息是27个字节” - 然后你知道只尝试读取27个字节,因为读取第28个可能会永远阻止你。在基于文本的协议中,这通常使用像换行这样的标记值来完成。