You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python连接服务器正常,Kotlin Ktor报Unsupported byte code错误

问题描述

我正在连接一台返回二进制数据的Web服务器,使用Python的Socket代码可以正常接收并输出结果:

from struct import unpack_from
import socket

HOST = "127.0.0.1"  
PORT = 12345  

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))

    while True:
        data = s.recv(7000)
        print(f"type: {type(data)}, size: {len(data)}, data: {data[0:10]}")

输出结果:

type: <class 'bytes'>, size: 6985, data: b'\x00\x00\x1bE\x00\x00\x00\x00\x10\x00'

但改用Ktor的WebSocket客户端代码连接时,却抛出异常 Exception: Unsupported byte code, first byte is 0x92:

import io.ktor.client.*
import io.ktor.client.plugins.websocket.*
import io.ktor.http.*
import io.ktor.websocket.*
import io.ktor.util.*
import kotlinx.coroutines.*


fun main() {
    val client = HttpClient {
        install(WebSockets)
    }
    runBlocking {
        client.webSocket(method = HttpMethod.Get, host = "127.0.0.1", port = 12345) {
            while(true) {
                val othersMessage = incoming.receive() as? Frame.Binary ?: continue
                println(othersMessage.readBytes())
            }
        }
    }
    client.close()
    println("Connection closed. Goodbye!")
}

解决思路

  • 核心原因:协议不匹配
    Python代码用的是普通TCP Socket直接连接,而Ktor代码用的是WebSocket协议。WebSocket是基于HTTP的升级协议,需要先完成握手(发送包含Upgrade: websocket的HTTP请求),如果你的服务器只是普通的TCP二进制服务,不支持WebSocket握手流程,那么它返回的二进制数据会被Ktor的WebSocket解析器错误地当成WebSocket帧来处理,自然触发解析异常。

  • 调试与验证步骤

    1. 抓包对比数据流:用Wireshark分别捕获两种连接的数据包,查看Ktor是否发送了WebSocket握手请求,以及服务器的响应内容。如果服务器返回的不是WebSocket握手响应,而是直接返回二进制数据,那肯定是协议不匹配。
    2. 确认服务器类型:明确服务器提供的是普通TCP服务还是WebSocket服务。可以用curl发送WebSocket握手请求测试:curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" ws://127.0.0.1:12345,如果返回101 Switching Protocols,说明是WebSocket服务;否则就是普通TCP服务。
    3. 检查WebSocket帧格式:如果服务器确实是WebSocket服务,那需要验证返回的帧是否符合RFC6455规范。异常中的0x92是帧的第一个字节,二进制为10010010:最高位是FIN位(1表示单帧完成),低4位Opcode是0x2(二进制帧),但中间的掩码位(第8位)如果是1,说明帧带了掩码,但服务器发送给客户端的帧不应该带掩码,这会导致Ktor解析失败。
  • 修复方案

    • 如果是普通TCP服务:放弃WebSocket客户端,改用Kotlin的java.net.Socket直接建立TCP连接,逻辑和Python代码对齐,示例代码大致如下:
      import java.net.Socket
      import kotlinx.coroutines.Dispatchers
      import kotlinx.coroutines.runBlocking
      import kotlinx.coroutines.withContext
      
      fun main() = runBlocking {
          withContext(Dispatchers.IO) {
              Socket("127.0.0.1", 12345).use { socket ->
                  val inputStream = socket.getInputStream()
                  val buffer = ByteArray(7000)
                  while (true) {
                      val bytesRead = inputStream.read(buffer)
                      if (bytesRead == -1) break
                      val data = buffer.copyOfRange(0, bytesRead)
                      println("type: ${data::class}, size: ${data.size}, data: ${data.take(10).joinToString(",") { "%02x".format(it) }}")
                  }
              }
          }
      }
      
    • 如果是WebSocket服务:检查服务器端的WebSocket帧生成逻辑,确保发送给客户端的帧没有添加掩码,并且帧的长度字段、Opcode等都符合RFC6455规范。

内容的提问来源于stack exchange,提问作者jake wong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 06:48:29