rpcConfig) {
+ if (rpcConfig.containsKey("serializer"))
+ this.serializerType = (String) rpcConfig.get("serializer");
+ if (rpcConfig.containsKey("server-port"))
+ this.serverPort = (Integer) rpcConfig.get("server-port");
+ if (rpcConfig.containsKey("server-host"))
+ this.serverHost = (String) rpcConfig.get("server-host");
+ if (rpcConfig.containsKey("protocol"))
+ this.protocol = (String) rpcConfig.get("protocol");
+ if (rpcConfig.containsKey("registry-address"))
+ this.registryAddress = (String) rpcConfig.get("registry-address");
+ if (rpcConfig.containsKey("registry"))
+ this.registryType = (String) rpcConfig.get("registry");
+ if (rpcConfig.containsKey("proxy"))
+ this.proxyType = (String) rpcConfig.get("proxy");
+ if (rpcConfig.containsKey("load-balancer"))
+ this.loadBalancer = (String) rpcConfig.get("load-balancer");
+ if (rpcConfig.containsKey("transport"))
+ this.transport = (String) rpcConfig.get("transport");
+ if (rpcConfig.containsKey("max-message-size"))
+ this.maxMessageSize = (Integer) rpcConfig.get("max-message-size");
+ if (rpcConfig.containsKey("worker-threads"))
+ this.workerThreads = (Integer) rpcConfig.get("worker-threads");
+ if (rpcConfig.containsKey("boss-threads"))
+ this.bossThreads = (Integer) rpcConfig.get("boss-threads");
+ if (rpcConfig.containsKey("max-connections"))
+ this.maxConnections = (Integer) rpcConfig.get("max-connections");
+
+ log.info("配置更新完毕: 序列化方式={}, 服务器={}:{},使用的协议={}, 注册中心={}, 代理方式={}, 负载均衡={}, 传输层={}, 最大报文={}",
+ serializerType, serverHost, serverPort, protocol, registryAddress, proxyType, loadBalancer,
+ transport, maxMessageSize);
}
/**
From f6a3c72d8db858c32ce7b444f9c1493dbcea70e7 Mon Sep 17 00:00:00 2001
From: yaojingxi <23722032@bjtu.edu.cn>
Date: Tue, 3 Mar 2026 11:18:18 +0800
Subject: [PATCH 21/22] =?UTF-8?q?feat:=E4=BD=BF=E7=94=A8=E9=AD=94=E6=95=B0?=
=?UTF-8?q?=E6=9D=A5=E8=BF=9B=E8=A1=8C=E5=8D=8F=E8=AE=AE=E5=97=85=E6=8E=A2?=
=?UTF-8?q?->TCP=20=3D=200xAABBCCDD,HTTP/2=20=3D=200x50524920?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../core/protocol/ProtocolDetectHandler.java | 122 ++++++++++++++++++
.../transport/netty/NettyTransportServer.java | 12 +-
2 files changed, 131 insertions(+), 3 deletions(-)
create mode 100644 rpc-transport-netty/src/main/java/com/xiaoyu/rpc/core/protocol/ProtocolDetectHandler.java
diff --git a/rpc-transport-netty/src/main/java/com/xiaoyu/rpc/core/protocol/ProtocolDetectHandler.java b/rpc-transport-netty/src/main/java/com/xiaoyu/rpc/core/protocol/ProtocolDetectHandler.java
new file mode 100644
index 0000000..84c9683
--- /dev/null
+++ b/rpc-transport-netty/src/main/java/com/xiaoyu/rpc/core/protocol/ProtocolDetectHandler.java
@@ -0,0 +1,122 @@
+package com.xiaoyu.rpc.core.protocol;
+
+import com.xiaoyu.rpc.core.server.NettyRpcHandler;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * 协议嗅探器 —— 服务端自动识别多种协议
+ *
+ * 原理:连接建立后,偷看(peek)入站数据的前几个字节,根据特征判断协议类型:
+ *
+ * - 0xAABBCCDD → TCP 私有协议(NettyProtocol)
+ * - 0x50524920 ("PRI ") → HTTP/2 Connection Preface(Http2Protocol 或
+ * GrpcProtocol)
+ * - HTTP 方法名(GET / POST / PUT / HEAD / DELETE / OPTIONS / PATCH)→
+ * HTTP/1.1(HttpProtocol)
+ *
+ * 识别后动态配置 pipeline 并移除自身,后续按确定的协议处理。
+ *
+ * 注意:gRPC 底层也是 HTTP/2 传输,无法在字节层面与普通 HTTP/2 区分。
+ * 通过构造函数的 {@code http2ProtocolName} 参数控制 HTTP/2 连接的处理方式。
+ */
+public class ProtocolDetectHandler extends ByteToMessageDecoder {
+
+ private static final Logger log = LoggerFactory.getLogger(ProtocolDetectHandler.class);
+
+ /** TCP 私有协议魔数,与 NettyRpcEncoder/NettyRpcDecoder 一致 */
+ private static final int NETTY_MAGIC = 0xAABBCCDD;
+
+ /** HTTP/2 Connection Preface 前 4 字节: "PRI " = 0x50524920 */
+ private static final int HTTP2_MAGIC = 0x50524920;
+
+ // 常见 HTTP/1.1 方法的首字母 ASCII 码
+ private static final byte BYTE_G = 'G'; // GET
+ private static final byte BYTE_P = 'P'; // POST, PUT, PATCH
+ private static final byte BYTE_D = 'D'; // DELETE
+ private static final byte BYTE_H = 'H'; // HEAD
+ private static final byte BYTE_O = 'O'; // OPTIONS
+ private static final byte BYTE_T = 'T'; // TRACE
+ private static final byte BYTE_C = 'C'; // CONNECT
+
+ /**
+ * 当检测到 HTTP/2 Connection Preface 时使用的协议名。
+ * 因为 gRPC 底层也是 HTTP/2,无法在字节层面区分,
+ * 所以通过这个参数指定:可以是 "http2" 或 "grpc"。
+ * 默认为 "http2"。
+ */
+ private final String http2ProtocolName;
+
+ /**
+ * 默认构造函数,HTTP/2 连接使用 Http2Protocol 处理
+ */
+ public ProtocolDetectHandler() {
+ this("http2");
+ }
+
+ /**
+ * 指定 HTTP/2 连接的处理协议
+ *
+ * @param http2ProtocolName HTTP/2 连接使用的协议名("http2" 或 "grpc")
+ */
+ public ProtocolDetectHandler(String http2ProtocolName) {
+ this.http2ProtocolName = http2ProtocolName;
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List