我的协议如下:
[size: UInt16][Channel: Uint16][Protobuff packet]
问题是,我的理解是tcp并不能保证用户发送的整个数据包都会全部到达。因此,技术上可能会出现这样的情况,即我不能立即获取整个消息,甚至是使用此消息发送另一条消息的一部分。
当我假设我将立即获取整个消息时,这很容易,因为我只是从流中读取前2个字节,创建了一个具有适当大小的缓冲区并调用read(buffer)
但是,如果我开始考虑切断的可能性,我不知道如何处理它。我尝试了以下方法:
val input = clientSocket.getInputStream()
while (!isStopped) {
val bufferedInputStream: BufferedInputStream = BufferedInputStream(input)
val dataInputStream: DataInputStream = DataInputStream(bufferedInputStream)
var messageSize: Int? = null
var channel: Int? = null
while (true) {
if (messageSize == null) {
messageSize = dataInputStream.readUnsignedShort()
}
if (channel == null) {
channel = dataInputStream.readUnsignedShort()
}
var bytesRead = 0
var didReachEnd = false
val buffer = ByteArray(messageSize - 4)
while (bytesRead != -1 && bytesRead != messageSize) {
val temp = dataInputStream.read(buffer)
if (temp == -1) {
didReachEnd = true
} else {
bytesRead += temp
}
Logger.debug(this::class.java, "bytes read: $bytesRead out of $messageSize")
}
val packet = ChatChannel.Packet.parseFrom(buffer)
print(packet.chatMessage.messageText)
}
}
我尝试通过从客户端套接字执行以下操作来模仿消息拆分:
val chatPacket = ChatChannel.Packet.newBuilder().setChatMessage(chatChannel).build()
val sendPacket = Packet(0,chatPacket.toByteArray())
val sendPacketByteArray = sendPacket.toByteArray()
val halfPoint = sendPacketByteArray.size/2
val firstSlice = sendPacketByteArray.sliceArray(IntRange(0,halfPoint))
val secondSlice = sendPacketByteArray.sliceArray(IntRange(halfPoint,halfPoint+(halfPoint%2)))
s.getOutputStream().write(firstSlice)
sleep(200)
s.getOutputStream().write(secondSlice)
但是我的实现只是在第二次运行时挂起在以下行:
bytesRead = dataInputStream.read(buffer,0,buffer.size)
我有一种感觉我不知道套接字是如何工作的,但是我看到的每个实现都假定当用户完成发送时他会关闭连接,但就我而言,它是一个聊天程序,所以用户只有在完成聊天时才会关闭连接。
我想要实现的目标:
size
的缓冲区已满编辑: 经过进一步的研究,我发现使用Java中的protobuf的MessageLite库似乎有一些名为writeDelimitedTo(outputStream)和parseDelimitedFrom(inputStream)的方法,所以看起来大部分工作都是为我完成的。
答案 0 :(得分:0)
两件事:
while (bytesRead != -1 && bytesRead != messageSize) {
bytesRead = dataInputStream.read(buffer,0,buffer.size)
对我来说似乎很奇怪。你没有增加bytesRead。也就是说,如果messageSize为100并且您在第一次读取时读取了90个字节,则在第二次读取时将读取10个字节。 你不能简单地说' bytesRead + = ...'因为它可能会返回-1。所以你需要另一个变量。检查返回值是否为非负值,然后将增量转换为byteCounter。需要将此byteCounter与messageSize进行比较。
另外:如果您所做的只是为Google protobuf消息提供多个频道,请不要这样做!创建包含protobuf消息和通道变量的protobuf消息。这应该会让生活变得更轻松。