检索可用数据的大小C#TCP NetworkStream [英] Retrieve Size of Data Available C# TCP NetworkStream

查看:67
本文介绍了检索可用数据的大小C#TCP NetworkStream的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够从C#中的tcp网络流中获取可用数据的长度,以便在从网络流中读取之前设置缓冲区的大小。有一个NetworkStream.Length属性,但它尚未实现,我不想为缓冲区分配一个巨大的大小,因为它会占用太多空间。我做这件事的唯一方法是在数据传输之前与另一个告诉大小,但这似乎有点混乱。对我这样做最好的方法是什么。



-Jordan

I would like to be able to get the length of the data available from a tcp network stream in C# to set the size of the buffer before reading from the network stream. There is a NetworkStream.Length property but it isn't implemented yet, and I don't want to allocate an enormous size for the buffer as it would take up too much space. The only way I though of doing it would be to precede the data transfer with another telling the size, but this seems a little messy. What would be the best way for me to go about doing this.

-Jordan

推荐答案

这是并不是说这个属性还没有尚未实施;这种实施没有任何意义。考虑网络流的本质:写入流的远程部分总是可以写入更多数据。另请注意,流是TCP数据包序列背后的抽象,因此,即使您可以确定包的大小,它也不会告诉您所有数据的预期大小,因为您事先并不知道如果所有数据甚至是全部发送的话。实际上,这是一些 应用程序层 协议的问题,该协议始终存在于一些 传输层 协议( TCP 或任何其他)。即使您没有为您的应用程序明确定义此类协议(但您最好这样做),它总是隐式存在。因此,这样的协议可能会或可能不会假设一些有限的流大小。如果与您的情况不同,它可能会假设无限地交换小消息。



那么,该怎么办?实际上,你已经有了一个完美的想法:在数据传输之前,另一个告诉大小。它根本不是凌乱,只是相反,这是你能做的最好的事情。您应该有意识地在您的应用层协议中正式且准确地包含此大小。它不必是以字节为单位的低级大小,也可以是发送元素的数量之类的东西。然后,如果每个元素也可以具有可变大小,则可以使用自己的大小为每个元素添加前缀,并且在撰写对象的情况下,可以按层次结构进行。这就是二进制序列化器的工作方式。因此,一种可选技术是使用二进制序列化器来处理数据。



-SA
It's not that this property is not "yet" implemented; such implementation would not make any sense. Think about the nature of network streams: a remote part writing to the stream can always write some more data. Also note that the stream is the abstraction behind the sequence of TCP packets, so, even though you can determine the size of the package, it does not tell you the expected size of all of the data, because you don't know in advance if all the data is even sent in full or not. Actually, this is a matter of some application-layer protocol, which always present on top of some transport-layer protocol (TCP or any other). Even you did not define such protocol explicitly for your applications (but you should better do it), it always exist implicitly. So, such protocol may or may not assume some finite stream size. In cases different from yours, it may assume "infinite" exchange of small messages.

So, what to do? Actually, you already had the perfect idea: "precede the data transfer with another telling the size". It's not "messy" at all, just to opposite, this is the best thing you can do. You should consciously include this size in your application-layer protocol, formally and accurately. It does not have to be "low-level" size in bytes, it could be, say, something like "number of sent elements". And then, if each element also can have variable size, you can preface each element with its own size, and in case of compose object, do it hierarchically. This is how, in particular, binary serializers work. So, one optional technique would be using a binary serializer for your data.

—SA


我已经回答了我的问题,但我会在这里发布给任何好奇的人,在没有发送任何辅助信息的情况下无法读取数据的长度,但是可以从流中加载块直到流是空,这是我用这些代码实现的:



发送:

I have answered my question but I'll post it here for anyone who is curious, it is impossible to read the length of the data without any secondary information being sent, however it is possible to load chunks off the stream until the stream is empty, this is what I have achieved with these pieces of code:

Send:
public void SendPacket(Packet pkt)
        {
            NetworkStream Stream = Socket.GetStream();
            Byte[] Buffer = pkt.Serialize();
            Byte[] Size = new Byte[8];
            long len = Buffer.Length;
            using (MemoryStream mem = new MemoryStream(Size))
            {
                using (BinaryWriter BW = new BinaryWriter(mem))
                {
                    BW.Write(len);
                }
            }
            Byte[] Bytes = new Byte[8 + Buffer.Length];
            Array.Copy(Size, Bytes, Size.Length);
            Array.Copy(Buffer, 0, Bytes, 8, Buffer.Length);
            Stream.Write(Bytes, 0, Bytes.Length);
        }





收到:



Receive:

private void StreamUpdater()
        {
            while(true){
                NetworkStream Stream = Socket.GetStream();
                if (Stream.DataAvailable)
                {
                    Byte[] Bytes = new Byte[0];
                    Byte[] buffer = new Byte[8];
                    Stream.Read(buffer, 0, 8);
                    long i;
                    using (MemoryStream mem = new MemoryStream(buffer))
                    {
                        using (BinaryReader BR = new BinaryReader(mem))
                        {
                            i = BR.ReadInt64();
                        }
                    }
                    long BiM = 0;
                    if(DataArrived != null)
                        DataArrived.Invoke(this, new TcpEventArgs(new Packet(Packet.Type.Null, null)));
                    Array.Clear(buffer, 0, 8);
                    Array.Resize(ref buffer, 1024);
                    while (BiM < i)
                    {
                        int bytesRead;
                        int BytesToRead = 1024;
                        if (BytesToRead > (i - BiM)) BytesToRead = (int)(i - BiM);
                        if ((bytesRead = Stream.Read(buffer, 0, BytesToRead)) > 0)
                        {
                            Array.Resize(ref Bytes, Bytes.Length + bytesRead);
                            Array.Copy(buffer, 0, Bytes, BiM, bytesRead);
                            BiM += bytesRead;
                            double percent = BiM / i;
                            percent = percent * 100;
                            PercentReceived = (int)percent;
                        }
                    }
                    Packet pkt = SerialMediator.Deserialize(Bytes);
                    if (DataAvailable != null)
                    {
                        DataAvailable.Invoke(this, new TcpEventArgs(pkt));
                    }
                }
            }
        }





忽略最后四行代码。 Packet和SerialMediator类是我用来包装服务器和客户端之间发送的数据的类,DataArrived是我创建的自定义事件。 TcpEventArgs是我创建的自定义EventArgs类。



Ignore the last four lines of code. The Packet and SerialMediator classes are classes I made to wrap up data being sent between the server and client, and the DataArrived is a custom event I created. The TcpEventArgs is a custom EventArgs class I created.


这篇关于检索可用数据的大小C#TCP NetworkStream的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆