簡體   English   中英

將套接字用於TCP上的自定義協議

[英]Using a socket for a custom protocol over tcp

我的協議如下所示:
[size: UInt16][Channel: Uint16][Protobuff packet]
問題是,據我了解,tcp不能保證用戶發送的整個數據包將一並到達。 因此,從技術上講,可能會出現這樣的情況,即我無法一次獲得全部消息,甚至無法與該消息一起發送另一條消息的一部分。

這很簡單,當我只是假設我將立即獲取整個消息時,因為我只是從流中讀取前2個字節,制作了一個具有適當大小的read(buffer)但是如果我開始,則稱為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已滿
  • 解析消息
  • 通知
  • 返回步驟0

編輯:經過進一步研究,我發現可以在Java中與protobuf一起使用的MessageLite庫似乎具有稱為writeDelimitedTo(outputStream)和parseDelimitedFrom(inputStream)的方法,因此似乎大部分工作已為我完成。

兩件事情:

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消息。 那應該使生活更加輕松。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM