假设您有一个连续的二进制数据流。每个数据的片段都应该以某种方式分割。最好的方法是什么?
Socket.read(byte [] arr)并不能保证你会收到与使用Socket.write发送完全相同的字节数(byte [] arr)arr可能被拆分(你首先读取的10个字节中有8个)然后2)或拼接。
解决此问题的方法之一是首先指定传入的字节数组的大小。准确读取4个字节,将它们转换为整数x,然后读取x个字节。但这只适用于TCP,如果只发送一次错误的字节数组
,可能会完全破坏所有内容我能想到的另一个是用伪随机字节序列为数据块添加前缀。使用种子在客户端和服务器上初始化Random,并使用random.nextBytes(byte [] arr)作为前缀。它的缺点是,为了确保在实际数据块中有一个随机序列的可能性非常小,你必须使它很长。这将增加许多无用的流量。同样,它不是UDP套接字的出路。
那么有什么其他好的方法呢?有没有简单的库可以让我简单地做conn.sendDataChunk(byte [] arr)?
答案 0 :(得分:1)
是的,这正是你应该做的。换句话说,您在每条消息之前添加了一个消息头。当您想要在没有消息边界概念的基于流的网络协议之上层叠基于消息的网络协议时,这是一种实际需要。 (TCP故意模糊IP数据包边界。)解决此问题的方法之一是首先指定传入的字节数组的大小。准确读取4个字节,将它们转换为整数x,然后读取x个字节。
您还可以使用此功能将其他字段添加到邮件标题中,例如邮件ID号,以帮助您区分不同的邮件类型。
但这只适用于TCP,如果只发送一次错误的字节数组大小,可能会完全破坏所有内容。
这是事实。所以不要发送格式错误的标题!
严肃地说,带有长度字段的标题是标准做法。在长度上添加健全性检查是个好主意:确保它不会太大(或消极),所以你最终不会分配2GB的内存来读取下一条消息。
此外,不要假设您可以使用单个read()
读取整个标头。获取整个标题可能需要多次读取。
答案 1 :(得分:0)
关于UDP套接字:读取UDP套接字与读取TCP套接字不同。您要么获得UDP数据包,要么不获得。来自UDP:
数据报 - 数据包是单独发送的,只有在到达时才会检查其完整性。数据包具有明确的边界,这些边界在接收时受到尊重,这意味着接收器插槽上的读取操作将产生最初发送的整个消息。
因此对于UDP,您不必担心读取不正确的字节数。但是你必须担心如果某些数据没有到达,或者它的到达顺序与发送的顺序不同,会发生什么。