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



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

未启动流表示的流

  • 流仅在处理和写入数据之后才提供其长度

例如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);
}

ConcatenatedStream是c#中建议的Stream实现-如何将两个System.Io.Stream实例连接为一个?-堆栈溢出。

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

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

PullStream将根据Read的需求对Write进行缓冲。

但这造成了一个大问题。在开始流式传输之前,我无法获取PullStream的长度。

任何帮助都将不胜感激。

感谢

让我们简单一点:

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

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

    这种情况是第一次执行时最难实现的3种情况。系好安全带。为了做正确的事情,你应该为你的流创建一个人工结构。这种结构用于通过网络传输视频,被称为网络抽象层(NAL)。它也被称为h264标准中的流格式附录B。你应该从描述标准的领域中抽象出来,这个想法是非常通用的。

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

    • 主数据有效载荷
    • 元数据

    在你想象了你的流应该是什么样子之后,你必须抓住"流编码"的想法。这些话很可怕,但别担心。您只需要确保用于标记NALU开始的字节序列在NALU的有效负载内永远不会满足要求。为了实现这一点,你将实施一些替代策略。浏览示例。

    当你思考完这个问题之后,在深入思考之前,三思而后行。也许场景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. 在这样的场景中,上传是不停止的,并且关于流的元数据在负载之后很长一段时间就在客户端上准备好了,这种情况也会发生,您将需要两个通道,即一个用于有效负载流的通道和另一个具有元数据的通道,服务器将用另一个问题回答客户端,如"您刚刚开始向我发送什么"或"您向我发送了什么",客户端将在下一条消息中解释自己

如果你准备坚持其中一种情况,可以给你一些进一步的细节和/或建议。

相关内容

  • 没有找到相关文章

最新更新