Netty 基本使用,比Mina要稳定的多。

项目里有个聊天的功能,之前一直用mina,一直有一个bug没解决,那就是断包、少包、和粘包的问题。

谷歌度娘了很多文章,可惜都以失败而告终。

这个问题很奇怪,就算做了处理,还是不行。

以下情况会出现那个bug

第一:当客户端与服务器保持连接时,如果长时间未发送过长的较长的消息(心跳一直有)的情况下,突然发送一条较长的json字符串,就会出现这个问题

第二:当客户端频繁与服务器进行数据传送,也会出现这个问题。

原字符串:

{"message":{"content":"gghh ","msgid":"1413260146146","userlogo":"http:\/\/192.168.1."userlogo":"http:\/\/192.168.1.21:8888\/upload\/image\/201435\/e0feff917266411290f1.jpg","nickname":"申兵兵","msgtype":0,"receiverUid":"8",21:8888\/upload\/image\/201435\/e0feff917266411290f1.jpg","nickname":"申兵兵","msgtype":0,"receiverUid":"8","userid":"7","sendUid":"7","timel":0,"ctime":"2014-10-14 12:15:46"},"sendUid":"7","msgid":"1413260146146","cmd":"order_sendmessage","receiverUid":"8"}


接收到的字符串:

{"message":{"content":"gghh ","msgid":"1413260146146","userid":"7","sendUid":"7","timel":0,"ctime":"2014-10-14 12:15:46"},"sendUid":"7","msgid":"1413260146146","cmd":"order_sendmessage","receiverUid":"8"}

"userlogo":"http:\/\/192.168.1.21:8888\/upload\/image\/201435\/e0feff917266411290f1.jpg","nickname":"申兵兵","msgtype":0,"receiverUid":"8",

你没有看错,将会以两次来接收,第一次接收头和尾,第二次接收了中间的,真是莫名其妙。

后来改成了Netty,上手还是很快的。

添加 netty-all-5.0.0.Alpha1.jar 就可以了

首先启动服务,注意,一定要在线程里启动,不过加入你的整个项目只有一个简单的main方法的话,可以无视

		        EventLoopGroup bossGroup = new NioEventLoopGroup();
		        EventLoopGroup workerGroup = new NioEventLoopGroup();
		        try {
		            ServerBootstrap b = new ServerBootstrap();
		            b.option(ChannelOption.SO_BACKLOG, 1024);
		            b.group(bossGroup, workerGroup)
		             .channel(NioServerSocketChannel.class)
		             .childHandler(new HttpHelloWorldServerInitializer());

		            Channel ch = b.bind(SocketManage.WORDPORT).sync().channel();
		            ch.closeFuture().sync();
		        }catch (Exception e) {
					e.printStackTrace();
				} finally {
		            bossGroup.shutdownGracefully();
		            workerGroup.shutdownGracefully();
		        }



HttpHelloWorldServerInitializer.class

public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> {
	
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast("timeout", new IdleStateHandler(60, 15, 0));//定时
        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
                8192, Delimiters.lineDelimiter()));
        pipeline.addLast("decoder", new StringDecoder(Charset.forName("utf-8")));
        pipeline.addLast("encoder", new StringEncoder(Charset.forName("utf-8")));
        pipeline.addLast("heartbeat", new MyHandler());//心跳
        pipeline.addLast("handler",new HttpHelloWorldServerHandler());//业务
    }
}


MyHandler.class 就是拦截心跳和发送心跳的

public class MyHandler extends SimpleChannelInboundHandler<String> {
     @Override
     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
         if (evt instanceof IdleStateEvent) {
             IdleStateEvent e = (IdleStateEvent) evt;
             if (e.state() == IdleState.READER_IDLE) {
//            	 System.out.println("--- Reader Idle ---");
//               ctx.close();
             } else if (e.state() == IdleState.WRITER_IDLE) {
//            	 System.out.println("--- Write Idle ---");
            	 ctx.writeAndFlush("#\n");
             }
         }
     }

	@Override
	protected void messageReceived(ChannelHandlerContext ctx, String str)
			throws Exception {
		if(str.equals("#")){
			return;
		}
		ctx.fireChannelRead(str);//传递到下一层,因为在HttpHelloWorldServerInitializer中注册了两个handelr,首先会进这里
	}
	
}


HttpHelloWorldServerHandler.class 与上一个MyHandler是一样的

public class HttpHelloWorldServerHandler extends SimpleChannelInboundHandler<String> {
   	@Override
	protected void messageReceived(ChannelHandlerContext ctx, String str)
			throws Exception {
		//str就是消息啦,在这里就可以进行业务逻辑了
	}
	
}

大功告成!!注意发消息和接收消息都要以\n结尾。




  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值