在不知道长度的情况下从 TcpClient.GetStream() 读取 [英] Read from TcpClient.GetStream() without knowing the length

查看:57
本文介绍了在不知道长度的情况下从 TcpClient.GetStream() 读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究基于 tcp 的通信协议.我所知有很多方法可以确定何时结束阅读.

  1. 在消息结束时关闭连接
  2. 将消息的长度放在数据本身之前
  3. 使用分隔符;一些永远不会出现在正常数据中的值(或者总是以某种方式转义)

<小时>

通常我会尝试通过 WiFi 网络发送文件(可能不稳定且速度低)

  • RSA 和 AES 通信的原因我不喜欢每次都关闭连接(不能使用 1)
  • 这是一个大文件,我无法预测它的长度,所以我无法采取行动作为方法(不能使用 2)
  • 读取时检查一些特殊的东西并在写入时将其转义需要很多过程(不能使用3)
  • 这个方法应该同时兼容c#和java.

你有什么建议?

<小时>

更一般的问题:

如何在java中识别InputStream的结尾

C# - TcpClient - 检测流结束?>

更多信息

我正在编写 TCP 客户端服务器通信

首先服务器生成一个 RSA 公共代码并将其发送给客户端.

然后客户端将生成 AES(key,IV) 并使用 RSA 加密将其发送回来.

到这里一切都很好.

但是我想通过这个网络发送一个文件.这是我当前的数据包 EncryptUsingAES(new AES.IV(16 byte) +file.content(any size))

在服务器中,我无法捕获客户端发送的所有数据.所以我需要知道要读取多少数据 (TcpClient.GetStream().read(buffer , 0 , buffersize) )当前代码:

Listmessage = new List();int 字节 = -1;做{字节[]缓冲区=新字节[缓冲区大小];bytes = stream.Read(buffer, 0, bufferrSize);如果(字节> 0){字节[] tmp = 新字节[字节];Array.Copy(buffer, tmp, bytes);消息.AddRange(tmp);}} while (bytes == bufferrSize);

解决方案

你的第二种方法是最好的.用数据包的长度为每个数据包添加前缀将创建一个可靠的消息帧协议,如果正确完成,它将确保接收到所有数据,即使它的大小与您发送的数据相同(即,没有部分数据或数据被混在一起).

  • 推荐的数据包结构:

    [数据长度(4 字节)][标题(1 字节)][数据(?? 字节)]

    - 有问题的标头是一个单字节,您可以使用它来指示这是什么类型的数据包,以便端点知道如何处理它.


发送文件

文件的发送者在 90% 的情况下都知道它将要发送的数据量(毕竟,它通常将文件存储在本地),这意味着知道有多少文件已发送没有问题.

我使用并推荐的方法是您首先发送一个信息包",它向端点解释它即将接收一个文件以及该文件包含多少字节.之后,您开始发送实际数据 - 最好是分块发送,因为一次处理整个文件效率低下(至少如果它是一个大文件).

  • 始终跟踪您到目前为止收到的文件的字节数.通过这样做,接收者可以自动判断它何时收到了整个文件.
  • 一次发送几千字节的文件(我使用 8192 字节 = 8 kB 作为文件缓冲区).这样您就不必将整个文件读入内存,也不必同时对其进行加密.


加密数据

处理加密不会有问题.如果您使用长度前缀,只需加密数据本身并保持数据长度标头不变.然后必须根据加密数据的大小生成数据长度标头,如下所示:

  1. 加密数据.
  2. 获取加密数据的长度.
  3. 生成以下数据包:

    [加密数据长度][加密数据]

    (如果需要,请在其中插入标题字节)


接收加密文件

接收加密文件并知道何时收到所有内容实际上并不难.假设您使用上述方法发送文件,您只需:

  1. 接收加密数据包 → 解密.
  2. 获取解密数据的长度.
  3. 增加一个变量来跟踪接收到的文件字节数.
  4. 如果收到的金额等于预期的金额:关闭文件.


其他资源/参考

您可以参考我之前写的关于 TCP 长度前缀消息帧的两个答案:

I'm working on a tcp base communication protocol . As i know there are many ways to determine when to end reading.

  1. Closing the connection at the end of the message
  2. Putting the length of the message before the data itself
  3. Using a separator; some value which will never occur in the normal data (or would always be escaped somehow)


Typically i'm trying to send a file over the WiFi network (that may be Unstable and Low speed)

  • Cause of RSA and AES communication I don't like to close the connection each time (Can't use 1)
  • It's a large file that i cant predict the length of it so i cant act as method (Can't use 2)
  • Checking for something special when reading and escape it when writing need a lot of process (Can't use 3)
  • This method should be compatible with both c# and java.

What you suggest ?


More general problems :

How to identify end of InputStream in java

C# - TcpClient - Detecting end of stream?

More Iformation

I'm coding a TCP client server communication

At first server generates and sends a RSA public code to the client.

Then the client will generate AES(key,IV) and send it back using RSA encryption.

Till here everything is fine.

But i want to send a file over this network. here is my current packet EncryptUsingAES(new AES.IV(16 byte) +file.content(any size))

In the server i can't capture all the data sent by client. So i need to know how much data to read with (TcpClient.GetStream().read(buffer , 0 , buffersize) ) Current code:

List<byte> message = new List<byte>();
    int bytes = -1;
    do
    {
        byte[] buffer = new byte[bufferrSize];
        bytes = stream.Read(buffer, 0, bufferrSize);
        if (bytes > 0)
        {
            byte[] tmp = new byte[bytes];
            Array.Copy(buffer, tmp, bytes);
            message.AddRange(tmp);
        }
    } while (bytes == bufferrSize);

解决方案

Your second method is the best one. Prefixing each packet with the packet's length will create a reliable message framing protocol which will, if done correctly, ensure that all your data is received even in the same size you sent it (that is, no partial data or data being lumped together).

  • Recommended packet structure:

    [Data length (4 bytes)][Header (1 byte)][Data (?? bytes)]
    

    - The header in question is a single byte you can use to indicate what kind of packet this is, so that the endpoint will know what to do with it.


Sending files

The sender of a file is in 90% of the cases aware of the amount of data it is about to send (after all, it usually has the file stored locally), which means there will be no problem knowing how much of the file has been sent or not.

The method I use and recommend is that you start by sending an "info packet", which explains to the endpoint that it is about to receive a file and also how many bytes that file consists of. After that you start sending the actual data - most preferrably in chunks since it's inefficient to proccess the entire file at once (at least if it's a large file).

  • Always keep track of how many bytes of the file you've received so far. By doing so the receiver can automatically tell when it has received the whole file.
  • Send a file a few kilobytes at a time (I use 8192 bytes = 8 kB as a file buffer). That way you don't have to read the entire file into memory nor encrypt it all at the same time.


Encrypting the data

Dealing with encryption will not be a problem. If you use length-prefixing just encrypt the data itself and leave the data length header untouched. The data length header must then be generated by the size of the encrypted data, like so:

  1. Encrypt the data.
  2. Get the length of the encrypted data.
  3. Produce the following packet:

    [Encrypted data length][Encrypted data]
    

    (Insert a header byte in there if you need to)


Receiving an encrypted file

Receiving an encrypted file and knowing when everything has been received is infact not very hard. Assuming you're using the above the described method for sending the file, you would just have to:

  1. Receive the encrypted packet → decrypt it.
  2. Get the length of the decrypted data.
  3. Increment a variable keeping track of the amount of file-bytes received.
  4. If the received amount is equal to the expected amount: close the file.


Additional resources/references

You can refer to two of my previous answers that I wrote about TCP length-prefixed message framing:

这篇关于在不知道长度的情况下从 TcpClient.GetStream() 读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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