NetworkStream 正在读取不应该存在的数据 [英] NetworkStream is reading data that should not be there

查看:21
本文介绍了NetworkStream 正在读取不应该存在的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

NetworkStream 从套接字缓冲区读取不应该存在的数据时遇到问题.顺便说一下,我正在发送非常大的缓冲区.现在我刚刚在本地主机上测试.

I have a problem with the NetworkStream reading data from the socket buffer that should not be there. I am sending very big buffers by the way. Right now I have just been testing on the localhost.

这是我读取数据的方式,前 4 个字节包含消息的长度,然后我只读取 4096 个块,直到达到消息的长度.

Here is how I read data, the first 4 bytes contain the length of the message, then I just read in 4096 chunks until it gets to the length of the message.

    protected TcpClient tcpObject;
    protected NetworkStream tcpStream;

    private void HandleComm()
    {
        try
        {
            tcpStream = tcpObject.GetStream();
            byte[] totalByteAray = new byte[constIntSize];
            byte[] message = new byte[constChunkSize];
            byte[] fullMessage = new byte[0];

            //this is how many bytes long the message will be
            int totalBytes = 0;
            int currentBytes = 0;
            int chunkSize = constChunkSize;

            while (true)
            {
                //skip reading if no data is available
                //DataAvailable does not tell you when all the data has arrived
                //it just tell you if some data has arrived
                if (tcpStream.CanRead)
                {
                    totalBytes = 0;
                    currentBytes = 0;
                    message = new byte[constChunkSize];
                    chunkSize = constChunkSize;

                    //The first 4 bytes of the message will always contain the length of the message, not including
                    //the first 4 bytes. This is how you know when to stop reading.
                    tcpStream.Read(totalByteAray, 0, constIntSize);                        
                    //there are 4 bytes in a 32 bit number, so totalByteArrayContains 4 index that is a byte which is
                    //the 32 bit int that tells us how many bytes the whole message will be.
                    //now convert the totalByteArray to a 32bit int
                    totalBytes = BitConverter.ToInt32(totalByteAray, 0);
                    Console.WriteLine("reading " + totalBytes);
                    //fullMessage will contain the entire message but it has to be built message by message.                    
                    fullMessage = new byte[totalBytes];
                    //keep reading until we get all the data
                    while (currentBytes < totalBytes)
                    {

                        //when you send something over TCP it will some times get split up
                        //this is why you only read in chuncks, 4096 is a safe amount of bytes
                        //to split the data into.
                        if (totalBytes - currentBytes < constChunkSize)
                        {
                            chunkSize = totalBytes - currentBytes;
                            message = new byte[chunkSize];
                        }

                        tcpStream.Read(message, 0, chunkSize);
                        //since we know each chunk will always come in at 4096 bytes if it doesn't that means that it's the end
                        //this part cuts off the extra empty bytes                           

                        //copy the message to fullMessage starting at current bytes and ending with the bytes left
                        message.CopyTo(fullMessage, currentBytes);
                        currentBytes += chunkSize;                            
                    }

                    //message has successfully been received
                    if (totalBytes != 0)
                    {

                        if (OnRawDataReceived != null)
                        {
                            RawDataReceivedArgs args = new RawDataReceivedArgs();
                            args.Data = new byte[fullMessage.Length];
                            fullMessage.CopyTo(args.Data, 0);
                            OnRawDataReceived(this, args);
                        }

                        totalBytes = 0;
                    }
                }
            }
        }
        catch
        {
            connectionStatus = ConnectionStatus.NotConnected;
            if (OnDisConnect != null)
                OnDisConnect(this, null);
        }
    }

这是我发送数据的方式,我只是获取消息的长度,然后创建一个新消息,其中前 4 个字节是消息的长度,其余是实际消息.

Here is how I am sending the data, I just get the length of the message and then create a new message with the first 4 bytes being the length of the message and the rest being the actual message.

    protected void sendData(byte[] data)
    {
        //we need to know how big the data that we are sending will be
        int length = data.Length;
        System.Console.WriteLine("writing " + length);
        //convert the 32bit int to a 4 byte array
        byte[] lengthArray = BitConverter.GetBytes(length);

        //init the main byte array that will be sent over
        byte[] buffer = new byte[length + constIntSize];

        //the first 4 bytes will contain the length of the data
        lengthArray.CopyTo(buffer, 0);

        //the rest of the buffer will contain the data being sent
        data.CopyTo(buffer, constIntSize);

        //wite it to the client stream
        tcpStream.Write(buffer, 0, length + constIntSize);
        //now send it
        tcpStream.Flush();           
    }

出于某种原因,我正在读取不应该在缓冲区中的数据.这是控制台输出.

For some reason I am getting reading data the shouldn't be on the buffer. Here is the console output.

服务器 ------------- 客户端

server ------------- client

写入 1024 -> 读取 1024

writing 1024 -> reading 1024

读取 1228800 <- 写入 1228800

reading 1228800 <- writing 1228800

写入 1024 -> 读取 1024

writing 1024 -> reading 1024

读取 1228800 <- 写入 1228800

reading 1228800 <- writing 1228800

阅读7224842

因此,当我单击一个按钮时,它会发送一个请求,说我想要来自网络摄像头的图像,请求是 1024 字节.客户端读取它并发送1228800字节的图像.我第一次这样做,它总是有效.我第二次点击它时,客户端发回了 1228800 个字节,服务器读取了正确的字节数,然后在套接字缓冲区应该为空时找到更多要读取的字节.我在套接字缓冲区中没有 7224842 字节,这正是读取的前 4 个字节所说的.

So when I click a button it sends a request saying I want a image from a web camera, the request is the 1024 bytes. The client reads it and sends the image which is the 1228800 bytes. The first time I do this, it always works. The second time I clicked it, the client sent back the 1228800 bytes, the server read the correct number of bytes and then found more bytes to read when the socket buffer should have been empty. I did not have 7224842 bytes in the socket buffer, that is just what the first 4 bytes of the read said.

关于为什么缓冲区会在其中获取额外数据的任何想法?当我发送较小的消息时,一切似乎都运行良好,但这让我发疯.

Any ideas of why the buffer is getting extra data in it? Everything seems to work well when I send smaller messages, but this is driving me crazy.

推荐答案

tcpStream.Read(totalByteAray, 0, constIntSize);
...
tcpStream.Read(message, 0, chunkSize);

然后我们就有了整个问题.要求检查返回到此.不能保证(对于基于网络的 IO,不太可能)您将一次获得整个缓冲区 - 数据包按时进入,API 将为您提供它所能提供的.相反,您会得到一些"(结果 > 0 和 <= 计数)或无"(结果 <= 0).

and there we have the entire problem. It is a requirement that you check the return to this. It is not guaranteed (and for network-based IO, pretty unlikely) that you will get the entire buffer all at once - packets come in as-and-when, and the API will give you what it can. Rather, you will get "some" (result > 0 and <= count) or "none" (result <= 0).

如果你想读取完全那么多的数据,那么写一个实用方法:

If you want to read exactly that much data, then write a utility method:

static void ReadExact(Stream stream, byte[] buffer, int offset, int count)
{
    int read;
    while(count > 0 && (read = stream.Read(buffer, offset, count)) > 0) {
        offset += read;
        count -= read;
    }
    if(count != 0) throw new EndOfStreamException();
}

这篇关于NetworkStream 正在读取不应该存在的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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