从TcpClient.GetStream()读取而不知道长度 - java

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

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

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

RSA和AES通信的原因我不想每次都关闭连接(不能使用1)
这是一个很大的文件,我无法预测它的长度,因此我无法采取行动
作为方法(不能使用2)
读取时检查特殊内容,写入时进行转义需要很多过程(不能使用3)
此方法应与c#和java兼容。

你有什么建议?

更一般的问题:

How to identify end of InputStream in java

C# - TcpClient - Detecting end of stream?

更多信息

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

首先,服务器生成RSA公共代码并将其发送到客户端。

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

直到这里一切都很好。

但我想通过该网络发送文件。这是我当前的数据包EncryptUsingAES(新AES.IV(16字节)+ file.content(任何大小))

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

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

参考方案

您的第二种方法是最好的方法。给每个数据包加上前缀长度将创建一个可靠的消息帧协议,如果正确完成,它将确保即使以与发送数据包相同的大小也能接收到所有数据(也就是说,没有部分数据或数据被集中在一起)。

推荐的报文结构:

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

-所讨论的标头是一个字节,您可以使用它指示这是哪种数据包,以便端点知道如何处理它。

发送文件

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

我使用并推荐的方法是从发送“信息包”开始,该信息包向端点说明它将要接收文件以及该文件包含多少字节。之后,您开始发送实际数据-最好是分块发送,因为一次处理整个文件效率不高(至少是大文件时如此)。

始终跟踪您到目前为止已收到文件的多少字节。这样,接收者可以自动知道何时接收到整个文件。
一次发送几个千字节的文件(我使用8192字节= 8 kB作为文件缓冲区)。这样,您不必将整个文件读入内存,也不必同时加密所有文件。

加密数据

处理加密将不会有问题。如果使用长度前缀,则只需对数据本身进行加密,并保持数据长度头不变。然后必须通过加密数据的大小来生成数据长度标头,如下所示:

加密数据。
获取加密数据的长度。
产生以下数据包:

[Encrypted data length][Encrypted data]

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

接收加密文件

实际上,接收加密文件并知道何时接收到所有内容并不是很困难。假设您使用上述发送文件的方法,则只需执行以下操作:

接收加密的数据包→将其解密。
获取解密数据的长度。
增加一个变量,以跟踪接收到的文件字节数。
如果收到的金额等于预期的金额:关闭文件。

其他资源/参考

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

C# Deserializing a struct after receiving it through TCP
TCP Client to Server communication

JAVA 8具有任何匹配属性的对象的过滤器列表 - java

我的要求是通过匹配任何属性的字符串来过滤对象列表。例如,假设Contact类具有三个属性:街道,城市,电话。我知道java流过滤器是如何工作的,在这里我必须将输入字符串与每个属性进行比较,如下所示:contactList.stream().filter(contact -> contact.getStreet().equals("dubai&…

检查Optional中是否存在null属性,并返回String Java Stream API - java

我有以下class Person private String firstName; private String familyName; // Setters and Getters 我有以下方法public String getFullName(Optional<Person> persons) { return persons .map(p…

Java:线程池如何将线程映射到可运行对象 - java

试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

JAVA:字节码和二进制有什么区别? - java

java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…

java:继承 - java

有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…