账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    netty tcp连接 出现大量CLOSE_WAIT
    19
    0

    LAST_ACK 5
    SYN_RECV 2
    CLOSE_WAIT 2
    ESTABLISHED 863
    FIN_WAIT1 22
    FIN_WAIT2 106
    TIME_WAIT 4698

    在ESTABLISHED 达到2000,CLOSE_WAIT逐步增高### 问题描述

    服务器 阿里云 4核16G, 运行时跑不满

    相关代码

    @Slf4j
    @Component
    public class NettyServer {

    private EventLoopGroup bossGroup;
    
    private EventLoopGroup workerGroup;
    
    @Autowired
    private NettyServerConfig nettyServerConfig;
    
    public void start() {
        //bossGroup线程池用来接受客户端的连接请求
        bossGroup = new NioEventLoopGroup();
        //workerGroup线程池用来处理boss线程池里面的连接的数据
        workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    
                    ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN,Integer.MAX_VALUE,0,4,2,4,true));
                    ch.pipeline().addLast(new IdleStateHandler(600, 600, 600, TimeUnit.SECONDS));//心跳600秒检测一次
                    ch.pipeline().addLast("handler", new NettyServerHandler());
                }
            });
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//检测客户端连接是否有效的参数
            
            ChannelFuture f = serverBootstrap.bind(nettyServerConfig.getPort()).sync();
            if(f.isSuccess()){
                log.info("TCP Server Start Success------Port---【" + nettyServerConfig.getPort() + "】");
                f.channel().closeFuture().sync();
            } else {
                log.error("TCP Server Start Failed------Port---【" + nettyServerConfig.getPort() + "】");
            }
        } catch (Exception e) {
            log.error("======nettyserver stop======", e);
            stop();
        }
    }
    
    public void stop(){
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
    

    }

    @Slf4j
    @Service
    public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * channelAction
     *
     * 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
     *
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    
        //设置连接时间
        Channel channel = ctx.channel();
    
        //加入定时清除任务
        NettyChannelManager.addTimeClear(channel);
    
    }
    
    /**
     * 当客户端主动断开服务端的 链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    
        try {
            Integer roomNumber = NettyChannelUtil.getRoomNumber(ctx.channel());
            if (roomNumber != null) {
                //退出房间
                GameNavigation gameNavigation = SpringContextHolder.getBean(GameNavigation.class);
                gameNavigation.exitRoom(ctx.channel());
            }
        } catch (Exception e) {
            log.error("channelInactive Exception", e);
        }
    
    }
    
    /**
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
    
        ByteBuf byteBuf = (ByteBuf) msg;
        try {
            int code = ByteBufUtil.readShort(byteBuf);
    
            byte[] bytes = ByteBufUtil.readBytes(byteBuf);
    
            GameNavigation gameNavigation = SpringContextHolder.getBean(GameNavigation.class);
            RoomProducer roomRequest = new RoomProducer();
            roomRequest.sendRoomRequest(code,bytes);
            gameNavigation.navigation(ctx.channel(), code, bytes);
    
        }catch (Exception e){
            log.error("channelRead Exception", e);
        } finally {
            byteBuf.release();
        }
    
    }
    
    /*
     * exceptionCaught
     *
     * exception    异常
     * Caught        抓住
     *
     * 抓住异常,当发生异常的时候,可以做一些相应的处理,比如打印日志、关闭链接
     *
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
    {
        try{
            if(cause.getClass() != IOException.class)
            {
                cause.printStackTrace();

    // close();

            }
    
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * 监听用户超时
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    
    }

    }

    你期待的结果是什么?实际看到的错误信息又是什么?

    0
    打赏
    收藏
    点击回答
        全部回答
    • 0
    • 夜歌云 普通会员 1楼

      "大量CLOSE_WAIT"是指一个连接的客户端和服务端在一段时间内保持在等待状态,这个时间通常为1分钟。这可能是由于网络连接不稳定或者客户端断开连接后没有及时关闭连接造成的。

      要解决这个问题,你可以尝试以下方法:

      1. 优化网络连接:检查你的网络连接,确保它稳定且没有断开。如果网络连接不稳定,可以尝试重启路由器或网络服务。

      2. 确保客户端断开连接:如果客户端在一段时间内没有关闭连接,服务器可能会保持连接状态,导致大量的CLOSE_WAIT。

      3. 使用客户端重试:如果客户端在一定时间内没有关闭连接,服务器可以尝试重试连接。这可以通过设置超时时间和重试次数来实现。

      4. 使用连接池:连接池可以管理网络连接,避免长时间的连接等待。当客户端断开连接后,服务器可以从连接池中获取一个新的连接。

      5. 使用TCP连接超时机制:TCP连接超时机制可以自动检测连接的完整性,如果连接在一定时间内没有关闭,服务器可以断开连接。

      6. 使用连接重连机制:连接重连机制可以在客户端断开连接后自动重新建立连接。这可以通过设置重连间隔时间和重连次数来实现。

      以上只是一些基本的解决方案,具体的方法可能需要根据你的网络环境和具体的问题来确定。

    更多回答
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部