将不确定流的长度传递给WCF服务

时间:2016-05-16 06:16:04

标签: c# wcf stream

有没有办法将不确定流的长度传递给WCF服务?

Unsertain Stream 表示

的流
  • 流只在处理和写入数据后才提供其长度。

e.g。的 GZipStream

背景

我正在制作一个WCF服务,从客户端接收多个流。

由于WCF Streaming只允许消息中有一个流,所以我决定将所有流连接成一个流,并将其划分为服务器代码。

客户端提供的流将包含可变类型的流,如FileStreamMemoryStream,其中包含来自DataTable序列化的数据和

using (var fileStream = new FileStream(filePath, FileMode.Open))
using (var memoryStream = new MemoryStream())
using (var concatStream = new ConcatenatedStream(fileStream, memoryStream))
{
    client.UploadStreams(concatStream);
}

ConcatenatedStreamc# - How do I concatenate two System.Io.Stream instances into one? - Stack Overflow中建议的Stream实施。

在服务器端,需要每个Streams的长度来将单个流划分为多个流。

由于我想在客户端节省内存,我决定使用 PullStream

PullStream 将根据Write的要求缓存Read

但这会引起一个大问题。在开始流式传输之前,我无法获得PullStream的长度。

任何帮助将不胜感激。

由于

1 个答案:

答案 0 :(得分:0)

让我们简单一点:

  1. 如果在开始将其推送到服务器之前在客户端上有一部分流的长度,则可以在有效负载之前附加结构并在服务器上读取该结构。这是一个标准的数据传输模板。这样做,即在每个有效负载之前附加一个标题,为服务器提供下一个部分的长度提示。

  2. 如果在开始将其推送到服务器之前在客户端上没有流的一部分长度,则必须在有效负载内“插入”标头。这不是很直观,没有用,但它确实有效。当我在客户端上异步准备我的数据并且在知道长度之前准备好第一个缓冲区时,我使用了这样的东西。在这种情况下,您将需要一个所谓的标记,即在流中的任何地方但在标题之前找不到的一组字节。

    这种情况是第一次完成时最难实现的3。系好安全带。为了做到正确,您应该创建流的人工结构。这种结构用于通过网络传输视频,并称为Network Abstraction Layer或NAL,阅读它。它也被称为来自h264标准的流格式AnnexB。你应该从描述标准的领域中抽象出来,这个想法是非常通用的。

    简而言之,有效载荷被分成多个部分,即所谓的NAL单元或NALU,每个部分都有一个字节序列,标记它的开始,然后是类型指示符和当前NALU的长度,然后跟随NALU的有效载荷。出于您的目的,您需要实现两种类型的NALU:

    • 主要数据有效负载
    • 元数据

    在想象出你的流应该是什么样子之后,你必须抓住“流编码”的想法。这些都是可怕的话,但不要担心。您只需确保在NALU的有效负载内永远不会遇到用于标记NALU起点的字节序列。为了实现这一点,你将实施一些替代战术。 Browse for samples.

    当你完成这段思考之后,在深入研究之前,请三思而后行。方案3可能更容易适合你。

    如果您确定永远不必处理流数据的一部分,则可以大大简化场景,即完全跳过流编码并实现以下内容:

  3. 客户Stream主要代码:

    private byte[] mabytPayload;
    private int mintCurrentPayloadPosition;
    
    private int? mintTotalPayloadLength;
    private bool mblnTotalPayloadLengthSent;
    
    public int Read(byte[] iBuffer, int iStart, int iLength)
    {
        if (mintTotalPayloadLength.HasValue && !mblnTotalPayloadLengthSent)
        {
            //1. Write the packet type (0)
            //3. Write the total stream length (4 bytes).
            ...
            mblnTotalPayloadLengthSent = true;
        }
        else
        {
            //1. Write the packet type (1)
            //2. Write the packet length (iLength - 1 for example, 1 byte is for
            //the type specification)
            //3. Write the payload packet.
            ...
        }
    }
    
    public void TotalStreamLengthSet(int iTotalStreamLength)
    {
        mintTotalPayloadLength = iTotalStreamLength;
    }
    

    服务器流阅读器:

    Public void WCFUploadCallback(Stream iUploadStream)
    {
        while(!endOfStream)
        {
            //1. Read the packet type.
            if (normalPayload)
            {
                //2.a Read the payload packet length.
                //2.b Read the payload.
            }
            else
            {
                //2.c Read the total stream length.
            }
        }
    }
    
    1. 在您的上传不停留并且有效负载之后很长时间内客户端上已准备好有关流的元数据的情况下,您将需要两个通道,即一个通道用于有效负载流,另一个通道用于元数据,您的服务器将回答客户端的另一个问题,如“你刚开始发送给我的是什么”或“你发给我的是什么”,客户将在下一条消息中解释自己。
    2. 如果您准备好坚持其中一个方案,可以给您一些进一步的细节和/或建议。