使用netty开发服务端出现异常

急!使用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}

目前已解决的问题:

  • (1)go客户端发送请求,java服务端能成功接收并处理;
  • (2)go发送心跳包,java服务端能成功接收并处理;
  • (3)go客户端发送请求,go服务端能成功接收并处理;
  • (4)go服务端发送请求,go客户端能成功接收并处理;

待解决问题:

  • (1)java服务端发送请求,go客户端能成功接收并处理;
  • (2)java客户端发送请求,go服务端能成功接收并处理;
不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^