简体   繁体   English

NetworkStream正在读取不应存在的数据

[英]NetworkStream is reading data that should not be there

I have a problem with the NetworkStream reading data from the socket buffer that should not be there. NetworkStream从套接字缓冲区读取不应存在的数据时遇到问题。 I am sending very big buffers by the way. 顺便说一下,我正在发送很大的缓冲区。 Right now I have just been testing on the localhost. 现在,我刚刚在本地主机上进行测试。

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. 这是我读取数据的方式,前4个字节包含消息的长度,然后我只读取4096个块,直到达到消息的长度。

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

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. 这是我发送数据的方式,我只获取消息的长度,然后创建一条新消息,其中前4个字节为消息的长度,其余为实际消息。

    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 服务器-------------客户端

writing 1024 -> reading 1024 写1024->阅读1024

reading 1228800 <- writing 1228800 阅读1228800 <-写1228800

writing 1024 -> reading 1024 写1024->阅读1024

reading 1228800 <- writing 1228800 阅读1228800 <-写1228800

reading 7224842 阅读7224842

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. 因此,当我单击一个按钮时,它会发送一个请求,说我要从网络摄像机获取图像,该请求为1024字节。 The client reads it and sends the image which is the 1228800 bytes. 客户端读取它并发送1228800字节的图像。 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. 我第二次单击它,客户端发回了1228800个字节,服务器读取了正确的字节数,然后在套接字缓冲区应该为空时发现了更多要读取的字节。 I did not have 7224842 bytes in the socket buffer, that is just what the first 4 bytes of the read said. 我在套接字缓冲区中没有7224842字节,这就是读取的前4个字节所说的。

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);

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 . 不能保证(对于基于网络的IO来说,几乎不可能)一次获得整个缓冲区-数据包随时间传入,并且API将为您提供所能提供的 Rather, you will get "some" (result > 0 and <= count) or "none" (result <= 0). 相反,您将获得“一些”(结果> 0和<=计数)或“无”(结果<= 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM