急!使用go-netty
开发服务端,刚启动服务端时,就不断出现读事件,而且没启动客户端,打开飞行模式也一样,可以排查外网的影响,而且之前在java的netty框架中启动服务端也不会出现不断的读事件,事件处理器这块是这样的。
这是初始化的配置到的处理器:
func initServerBootstrap(serverHandler netty.ChannelHandler, commonCodec netty.CodecHandler) netty.Bootstrap {
var childInitializer = func(channel netty.Channel) {
channel.Pipeline().
//AddLast(netty.ReadIdleHandler(time.Second * 3)).
//AddLast(netty.WriteIdleHandler(time.Second * 5)).
//AddLast(commonCodec)
AddLast(serverHandler)
}
return netty.NewBootstrap(netty.WithChildInitializer(childInitializer))
}
这是该处理器
package server
import (
"fmt"
"github.com/go-netty/go-netty"
)
func NewServerHandler() netty.ChannelHandler {
return &serverHandler{}
}
type serverHandler struct{}
func (h *serverHandler) HandleActive(ctx netty.ActiveContext) {
//TODO implement me
}
func (h *serverHandler) HandleWrite(ctx netty.OutboundContext, message netty.Message) {
//TODO implement me
fmt.Println("HandleWrite")
fmt.Println("服务端触发写操作:这是写操作信息: ", message)
//ctx.Write(message)
}
func (h *serverHandler) HandleInactive(ctx netty.InactiveContext, ex netty.Exception) {
//TODO implement me
}
func (h *serverHandler) HandleRead(ctx netty.InboundContext, message netty.Message) {
// 在这里处理已经解码的消息
// 根据您的具体业务逻辑进行处理
// 示例:打印消息内容
fmt.Println("服务端读到客户端消息: ", message)
// 示例:发送响应消息
//response := "Hello, Client!"
//ctx.Write(response)
}
func (h *serverHandler) HandleException(ctx netty.ExceptionContext, ex netty.Exception) {
// 处理异常情况
fmt.Println("Exception caught:", ex)
ctx.Close(ex)
}
这是控制台打印:
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc000402050 false}
服务端读到客户端消息: &{0xc0002e2000 false}
服务端读到客户端消息: &{0xc0002e2000 false}
服务端读到客户端消息: &{0xc0004020a0 false}
服务端读到客户端消息: &{0xc0004020a0 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc0002e2050 false}
服务端读到客户端消息: &{0xc00038e0a0 false}
服务端读到客户端消息: &{0xc00038e0a0 false}
服务端读到客户端消息: &{0xc00038e0a0 false}
需要补充可以告知。
------------------------------------------------------------ 2023/7/24/ 17:40 -------------------------------------------
原因已找到,但出现了新的问题了。
是因为我启动的时候,将服务注册到了nacos上,nacos这个注册相关api函数获取了我本地ip,nacos注册中心会主动发送心跳或者请求检测服务是否可用,因为如果我在本地关闭服务,nacos可以发现服务会变成不可用状态,可能这个原因很大。
但是它服务端读事件频率太高了,是一直在循环不断地读操作,就在我删除这个注册服务代码,启动服务端后不再出现循环读事件。
但我通过浏览器去访问本地端口,访问一次后关闭浏览器,服务端仍在不断读事件,这个问题是如何导致的?
------------------------------------------------------------ 2023/7/24/ 18:09 -------------------------------------------
谢谢大家,问题已解决,HandlerRead读取到消息后,要记得关闭,不然会再次触发,关闭后相当于flush掉通道了。就不会重复读取到通道缓存。
当然后续有问题会从下面再次给出。
------------------------------------------------------------ 2023/7/26/ 19:13 -------------------------------------------
目前搭建RPC框架过程中:
尝试 go 客户端通信go服务端,客户端发送写事件服务端读事件可以触发;(快)
尝试 go 服务端再次发送写事件到channel,go 客户端读事件也可以触发;(快)
尝试 go 客户端请求java服务端,请求可以成功,go 客户端发送写事件,java服务端触发读事件;(快)
尝试 go 客户端等待java服务端结果发送写事件,go 客户端无法接收(读事件不触发或延迟触发【非常久】 java 服务端已经多次重试失败后放弃该笔请求了);
尝试java客户端发送写事件,go服务端接收(延迟或无接收)
思考:
(1)受注册中心干扰,尝试直连方式无果,同上;
(2)go客户端与go服务端双向通信,java客户端与java服务端可以双向通信,与通信协议有关,前面测试延迟说明协议是可行的,协议应该不太可能影响到延迟或无接收;
(3)框架设计问题,go-netty与Netty(Java)之间兼容性;
(4)进程与线程问题,go存在协程?
----------------------------------------------------------- 2023/7/27/ 18:36 -------------------------------------------
解决方案:
go服务端:
var clientnitializer = func(channel netty.Channel) {
channel.Pipeline().
// 最大允许包长128字节,使用\n分割包, 丢弃分隔符
AddLast(frame.DelimiterCodec(1024, "\r\n", true)).
//AddLast(frame.LengthFieldCodec(binary.BigEndian, 2048, 8, 2, 12, 0)).
AddLast(netty.ReadIdleHandler(time.Second*3), netty.WriteIdleHandler(time.Second*5)).
AddLast(codec.CommonCodec(0, 8, 71, 1)).
AddLast(client.NewClientHandler())
}
java客户端
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer("\r\n", CharsetUtil.UTF_8)))
.addLast(new IdleStateHandler(3, 5, 7, TimeUnit.SECONDS))
.addLast(new CommonDecoder())
.addLast(new CommonEncoder(serializer))
.addLast(new NettyClientHandler());
/**
* 读 channel --> 解码 --> (注册检测心跳包,后面自己会检测) --> 处理客户端 --> 编码 --> 写 channel
*/
}
});
不过只能让服务端接收到客户端的请求,但这个java客户端的请求到服务端会出现异常,应该是框架设计上的不同语言的兼容性导致,由于个人对netty底层不够深入理解,目前还未能成功解决根本问题:
Exception caught: frame length too large, readBuffLength(1024) >= maxFrameLength(1024)
go控制台:
-> active: 127.0.0.1:9528
HandleWrite
客户端触发写操作:这是写操作信息: &{123455 helloService sayH ello [hello,这里是go语言] [java.lang.String] java.lang.String false 1.0.1 false }
codec 准备写入数据,正在编码
message &{123455 helloService sayHello [hello,这里是go语言] [java.lang.String] java.lang.String false 1.0.1 false}
序列化后的数据长度: 235
2023/07/27 19:25:15 Send heartbeat packets to server[%s] 127.0.0.1:9528
java控制台
19:25:10.136 [INFO] io.netty.handler.logging.LoggingHandler [nioEventLoopGroup-2-1] - [id: 0xc22d269b, L:/0:0:0:0:0:0:0:0:9528] READ: [id: 0xa7108e76, L:/127.0.0.1:9528 - R:/127.0.0.1:61838]
19:25:10.137 [INFO] io.netty.handler.logging.LoggingHandler [nioEventLoopGroup-2-1] - [id: 0xc22d269b, L:/0:0:0:0:0:0:0:0:9528] READ COMPLETE
validateAndHandlerRequestRpcRequest{requestId='123455', interfaceName='helloService', methodName='sayHello', parameters=[hello,这里是go语言], paramTypes=[class java.lang.String], returnType=class java.lang.String, reSend=false, group='1.0.1', heartBeat=false}
19:25:10.148 [INFO] cn.fyupeng.net.netty.server.NettyChannelDispatcher [operation-executor-pool-6] - server has received request package: RpcRequest{requestId='123455', interfaceName='helloService', methodName='sayHello', parameters=[hello,这里是go语言], paramTypes=[class java.lang.String], returnType=class java.lang.String, reSend=false, group='1.0.1', heartBeat=false}
19:25:10.148 [INFO] cn.fyupeng.net.netty.server.NettyChannelDispatcher [operation-executor-pool-6] - [requestId: 123455, reSend: false] does not exist, store the result in the distributed cache
19:25:10.148 [INFO] cn.fyupeng.handler.JdkRequestHandler [operation-executor-pool-6] - Proxy target Service cn.fyupeng.service.HelloWorldServiceImpl@db404a7
19:25:10.148 [INFO] cn.fyupeng.handler.JdkRequestHandler [operation-executor-pool-6] - Service: helloService is invoking method [sayHello], paramTypes [[class java.lang.String]] ,parameters [[hello,这里是go语言]]
19:25:10.206 [INFO] cn.fyupeng.handler.JdkRequestHandler [operation-executor-pool-6] - Service: helloService completed the method [sayHello] call
19:25:10.206 [INFO] cn.fyupeng.handler.JdkRequestHandler [operation-executor-pool-6] - ==> Task execution takes 58 ms
19:25:10.206 [INFO] cn.fyupeng.net.netty.server.NettyChannelDispatcher [operation-executor-pool-6] - server send back response package {requestId: 123455, message: ok, statusCode: 200 ]}
validateAndHandlerRequestRpcRequest{requestId='', interfaceName='', methodName='', parameters=[], paramTypes=[], returnType=null, reSend=false, group='', heartBeat=true}
目前已解决的问题:
待解决问题: