netty9---使用编码解码器
客户端:
package com.client; import java.net.InetSocketAddress; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import com.cn.codc.RequestEncoder; import com.cn.codc.ResponseDecoder; import com.cn.model.Request; import com.cn.module.fuben.request.FightRequest; /** * netty客户端入门 */ public class Client { public static void main(String[] args) throws InterruptedException { //服务类 ClientBootstrap bootstrap = new ClientBootstrap(); //线程池 ExecutorService boss = Executors.newCachedThreadPool(); ExecutorService worker = Executors.newCachedThreadPool(); //socket工厂 bootstrap.setFactory(new NioClientSocketChannelFactory(boss, worker)); //管道工厂 bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("decoder", new ResponseDecoder());//Response解码器 pipeline.addLast("encoder", new RequestEncoder());//Request编码器 pipeline.addLast("hiHandler", new HiHandler());//通过ResponseDecoder解码的是一个Response对象。 return pipeline; } }); //连接服务端 ChannelFuture connect = bootstrap.connect(new InetSocketAddress("127.0.0.1", 10101)); Channel channel = connect.sync().getChannel(); System.out.println("client start"); Scanner scanner = new Scanner(System.in); while(true){ System.out.println("请输入"); int fubenId = Integer.parseInt(scanner.nextLine()); int count = Integer.parseInt(scanner.nextLine()); FightRequest fightRequest = new FightRequest(); fightRequest.setFubenId(fubenId); fightRequest.setCount(count); Request request = new Request(); request.setModule((short) 1);//请求第一个模块的 request.setCmd((short) 1); request.setData(fightRequest.getBytes());//fightRequest是数据体data //发送请求 channel.write(request); } } }
package com.client; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import com.cn.model.Response; import com.cn.model.StateCode; import com.cn.module.fuben.request.FightRequest; import com.cn.module.fuben.response.FightResponse; /** * 消息接受处理类 */ public class HiHandler extends SimpleChannelHandler { /** * 接收消息 */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Response message = (Response)e.getMessage();//解码出来的之后是Response对象,然后进行业务处理 if(message.getModule() == 1){ if(message.getCmd() == 1){ FightResponse fightResponse = new FightResponse(); fightResponse.readFromBytes(message.getData()); System.out.println("gold:" + fightResponse.getGold()); }else if(message.getCmd() == 2){ } }else if (message.getModule() == 1){ } } /** * 捕获异常 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { System.out.println("exceptionCaught"); super.exceptionCaught(ctx, e); } /** * 新连接 */ @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelConnected"); super.channelConnected(ctx, e); } /** * 必须是链接已经建立,关闭通道的时候才会触发 */ @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelDisconnected"); super.channelDisconnected(ctx, e); } /** * channel关闭的时候触发 */ @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelClosed"); super.channelClosed(ctx, e); } }
服务端:
package com.server; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import com.cn.codc.RequestDecoder; import com.cn.codc.ResponseEncoder; /** * netty服务端入门 */ public class Server { public static void main(String[] args) { //服务类 ServerBootstrap bootstrap = new ServerBootstrap(); //boss线程监听端口,worker线程负责数据读写 ExecutorService boss = Executors.newCachedThreadPool(); ExecutorService worker = Executors.newCachedThreadPool(); //设置niosocket工厂 bootstrap.setFactory(new NioServerSocketChannelFactory(boss, worker)); //设置管道的工厂 bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("decoder", new RequestDecoder());//Request的解码器 pipeline.addLast("encoder", new ResponseEncoder());//Response的编码器 pipeline.addLast("helloHandler", new HelloHandler()); return pipeline; } }); bootstrap.bind(new InetSocketAddress(10101)); System.out.println("start!!!"); } }
package com.server; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import com.cn.model.Request; import com.cn.model.Response; import com.cn.model.StateCode; import com.cn.module.fuben.request.FightRequest; import com.cn.module.fuben.response.FightResponse; /** * 消息接受处理类 */ public class HelloHandler extends SimpleChannelHandler { /** * 接收消息 */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Request message = (Request)e.getMessage(); if(message.getModule() == 1){ if(message.getCmd() == 1){ FightRequest fightRequest = new FightRequest(); fightRequest.readFromBytes(message.getData()); System.out.println("fubenId:" +fightRequest.getFubenId() + " " + "count:" + fightRequest.getCount()); //回写数据 FightResponse fightResponse = new FightResponse(); fightResponse.setGold(9999); Response response = new Response(); response.setModule((short) 1); response.setCmd((short) 1); response.setStateCode(StateCode.SUCCESS); response.setData(fightResponse.getBytes()); ctx.getChannel().write(response); }else if(message.getCmd() == 2){ } }else if (message.getModule() == 1){ } } /** * 捕获异常 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { System.out.println("exceptionCaught"); super.exceptionCaught(ctx, e); } /** * 新连接 */ @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelConnected"); super.channelConnected(ctx, e); } /** * 必须是链接已经建立,关闭通道的时候才会触发 */ @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelDisconnected"); super.channelDisconnected(ctx, e); } /** * channel关闭的时候触发 */ @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelClosed"); super.channelClosed(ctx, e); } }
网络传的是字节数据不是字符。
Netty之自定义数据包协议:
give me a coffee give me a tea (2条信息)
give me a coffeegive me a tea 粘包现象(2条信息粘在一起)
give me
a coffeegive me a tea 分包现象(第一条消息分开了,第一条后部分又粘到了第二条消息)
粘包和分包出现的原因是:没有一个稳定数据结构(没有确定一个请求传递哪些数据)
分割符:
give me a coffee|give me a tea|
give me a coffee|
give me a tea|
长度 + 数据:
16give me a coffee13give me a tea(读取16个就封装成一个请求,投递到业务层去)
16give me a coffee
13give me a tea