netty框架学习之初始篇---多客户端的实现补充部分

上一篇文章中并没有太过详细的讲解,而且经过今天一天的瞎搞,弄清了几个问题,于是在这里先补充一下,也有几个地方对前面的文章做一下修正。

1.关于HelloServerInitializer(后面我改成了ServerInitalizer,毕竟项目不能叫做hello什么吧。。。),在ServerInitializer中添加的解码编码器,前面文章说明有点问题,经过测试,并非一定要配置解码编码器才能通讯,如果采用byte类型的数据通讯时没有问题的,只需要有自己的逻辑处理部分就行。但是另一问题也随之而来,数据类型的转换,太费劲了。。。还是建议加上netty自带的解码编码器

另外,ServerSimpleHandler继承的类可以是SimpleChannelInboundHandler,也可以是ChannelInboundHandlerAdapter

SimpleChannelInboundHandler继承了ChannelInboundHandlerAdapter

至于其他的还没测试,这两个作为父类的时候子类所需要实现的方法并不相同,ChannelInboundHandlerAdapter要实现的关键方法是channelRead(ChannelHandlerContext ctx, Object msg),而不是channelRead0();而且注意channelRead方法的第二个参数是object类,这与SimpleChannelInboundHandler中的channelRead0(ChannelHandlerContext ctx, I msg)不同,channelRead0这个方法的第二个参数是一个I,一开始也是一头雾水,后来发现,public abstract class SimpleChannelInboundHandler,也就是说,第二个参数与父类的参数类型保持一致,瞬间明悟了。一开始我局限于SimpleChannelInboundHandler,以为这里只能是String,原来这里可以使任何类型的数据,于是我改成了byte[],因为我需要处理byte数据,而且尽管这里也可以写成object,但是当你发现用bytebuf去处理数据类型转换的时候是何等的费劲,还不如直接写明这里需要什么数据,这样在ServerInitializer中配置解码编码器的时候就要加上byte的解码编码器了。如下代码

package com.yl.netty.server;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.base64.Base64Decoder;
import io.netty.handler.codec.base64.Base64Encoder;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class ServerInitializer extends ChannelInitializer{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        // 以("\n")为结尾分割的 解码器
//        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));

        // 字符串解码 和 编码
//        pipeline.addLast("decoder", new StringDecoder());//解码
//        pipeline.addLast("encoder", new StringEncoder());//编码
        pipeline.addLast("bytesDecoder",new ByteArrayDecoder());
        pipeline.addLast("bytesEncoder",new ByteArrayEncoder());
//        pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
//        pipeline.addLast("Encoder",new ObjectEncoder());
        // 自己的逻辑Handler
        pipeline.addLast("handler", new ServerSimpleHandler());
    }
}
上面的代码可以看到,最后一个pipeline.addLast("handler", new ServerSimpleHandler());

这个是自己的逻辑handler。

public class ServerSimpleHandler extends SimpleChannelInboundHandler {
 /**
     * 覆盖了 channelRead0() 事件处理方法。每当从服务端读到客户端写入信息时,将信息转发给其他客户端的 Channel。
     */
	
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] msg) throws Exception {
    	Channel channel = ctx.channel();
    	hexStrMsg= StringUtil.bytesToHexString(msg);// 转换为十六进制字符串
		strMsg = new String(msg, 0, msg.length);
		System.out.println("7/string-->>>" + hexStrMsg);
		System.out.println("8/string-->>>" + strMsg);
		//遍历获取到的设备信息
    	for (int i = 0; i < PublicHelp.deviceConfigList.size(); i++) {
    		//检测设备id是否存在如果存在,那么将其添加到map中。
    		if(strMsg.equals(PublicHelp.deviceConfigList.get(i).getTxmkid())){
    			PublicHelp.channelMap.put(strMsg,channel);
    			txmkid = strMsg;
        	}
    		//检测心跳数据,如果有与之匹配的心跳,更新map
    		if(strMsg.equals(PublicHelp.deviceConfigList.get(i).getTxmkxt())){
    			PublicHelp.channelMap.put(PublicHelp.deviceConfigList.get(i).getTxmkid(),channel);
        	}
		}
    	//遍历设备信息,查看获得的消息是否是php端发送的有订单消息
		if (hexStrMsg.substring(0,6).equals(PublicHelp.deviceConfigList.get(0).getPhpmsg().substring(0, 3))) {
			ReceiveMsgDao.saveRecMsg("php--" + hexStrMsg);
			for (int i = 0; i < PublicHelp.deviceConfigList.size(); i++) {
				if(hexStrMsg.equals(PublicHelp.deviceConfigList.get(i).getPhpmsg())){
					ordermsg = ReceiveMsgDao.getTemp1OrderMsg();
					jqid = ordermsg[2];
				}
			}

		}
上面是部分代码并不完整,还没整理完,而且也没法贴上完整代码。只是想说明SimpleChannelInboundHandler问题。上面代码也能看出是如何区分不同的客户端的。

而且我做了测试,每当一个client连接到server 的时候,ServerSimpleHandler 类就会重新new一个新的出来,也就是说,如果你在该类中定义了变量如果不是静态的,那么每次有新的client接入的时候,各个客户端之间是无法通过这些变量进行信息交互的,所以我将这些需要共享的信息放在了一个公共类中,把类中的方法变量都静态化,减少类的重复实例化。这种情况对于多客户端通信是很有利的,因为很多私有变量不需要特殊去声明或者找一个单独的类对象去维护,只需要在ServerSimpleHandler 类中直接定义就行,该类每次实例化一个对象的时候其中的局部变量就自动私有化了。至少对于我现在要更改的项目来说是有利的。


爱编程,爱学习,爱挑战。

程序猿就是我,我就是程序猿。





你可能感兴趣的:(工作,java)