Netty学习笔记(一)二进制流协议【转】

15 篇文章 0 订阅

一、协议

1. 请求:

 

字段

类型

说明

length

short

消息长度

commandid

short

消息类型

userid

int

用户号

2. 响应:

 

 

字段

类型

说明

length

short

消息长度

commandid

short

消息类型

userid

int

用户号

result

byte

0: 成功

1: 失败

二、编解码代码

public abstract class KaMessage {

 

protected short commandId;

 

 

protected int userId;

 

public static final short HEADLENGTH = 6;

 

public static final short REQ = 0x0001;

 

public static final short RES = 0x1001;

 

 

 

 

public void encode(ByteBuffer buffer) {

buffer.putInt(userId);

subencode(buffer);

}

 

public void decode(ByteBuffer buffer) {

userId = buffer.getInt();

subdecode(buffer);

}

 

public abstract short length();

 

public abstract void subencode(ByteBuffer buffer);

 

public abstract void subdecode(ByteBuffer buffer);

 

public int getUserId() {

return userId;

}

 

public void setUserId(int userId) {

this.userId = userId;

}

 

public short getCommandId() {

return commandId;

}

}

 

public class KaRes extends KaMessage {

 

private short result = 200;

 

public KaRes() {

commandId = KaMessage.RES;

}

 

@Override

public short length() {

// TODO Auto-generated method stub

short len = KaMessage.HEADLENGTH;

len += 2;

return len;

}

 

@Override

public void subencode(ByteBuffer buffer) {

// TODO Auto-generated method stub

buffer.putShort(result);

}

 

@Override

public void subdecode(ByteBuffer buffer) {

// TODO Auto-generated method stub

result = buffer.getShort();

}

 

@Override

public String toString() {

// TODO Auto-generated method stub

StringBuffer sb = new StringBuffer();

sb.append(super.toString());

sb.append(" - result: " + result);

return sb.toString();

}

 

public short getResult() {

return result;

}

 

public void setResult(short result) {

this.result = result;

}

 

}

 


public class KaReq extends KaMessage {

 

 

 

 

public KaReq() {

commandId = KaMessage.REQ;

}

 

@Override

public void subencode(ByteBuffer buffer) {

// TODO Auto-generated method stub

}

 

@Override

public short length() {

// TODO Auto-generated method stub

short len = PaMessage.HEADLENGTH;

 

 

return len;

}

 

@Override

public void subdecode(ByteBuffer buffer) {

// TODO Auto-generated method stub

}

}

 

 

public class KaCodecUtil {

 

public static byte[] NetEncode(PaMessage message) {

ByteBuffer buffer = ByteBuffer.allocate(message.length() + 2);

buffer.putShort(message.length());

buffer.putShort(message.getCommandId());

message.encode(buffer);

return buffer.array();

}

 

public static KaMessage NetDecode(byte[] data) {

ByteBuffer buffer = ByteBuffer.wrap(data);

short commandId = buffer.getShort();

PaMessage message = null;

switch(commandId) {

case KaMessage.SEQ:

message = new KaReq();

message.decode(buffer);

return message;

case KaMessage.Res:

message = new KaRes();

message.decode(buffer);

return message;

 

 

}

return message;

}

 


public class KaEncoder extends OneToOneEncoder {

@Override

protected Object encode(ChannelHandlerContext context, Channel channel,

Object object) throws Exception {

// TODO Auto-generated method stub

KaMessage message = (KaMessage)object;

ChannelBuffer buf = ChannelBuffers.dynamicBuffer();

buf.writeBytes(KaCodecUtil.NetEncode(message));

return buf;

}

}

 

 

public class KaDecoder extends FrameDecoder {

 

@Override

protected Object decode(ChannelHandlerContext context, Channel channel,

ChannelBuffer buffer) throws Exception {

// TODO Auto-generated method stub

if(buffer.readableBytes() < 2) {

buffer.resetReaderIndex();

return null;

}

short length = buffer.readShort();

if(buffer.readableBytes() < length) {

buffer.resetReaderIndex();

return null;

}

byte[] decode = new byte[length];

buffer.readBytes(decode);

KaMessage message = KaCodecUtil.NetDecode(decode);

return message;

}

 

}


二、服务端代码

public class ServerBoot {

 

public static void main(String[] args) {

ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() {

 

 

public ChannelPipeline getPipeline() {

ChannelPipeline pipeline = Channels.pipeline();

pipeline.addLast("decoder", new KaDecoder());

pipeline.addLast("encoder", new KaEncoder());

pipeline.addLast("handler", new KaHandler());

return pipeline;

}

};

 

ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());

ServerBootstrap bootstrap = new ServerBootstrap(factory);

bootstrap.setPipelineFactory(pipelineFactory);

bootstrap.setOption("child.tcpNoDelay", true);

bootstrap.setOption("child.keepAlive", true);

bootstrap.bind(new InetSocketAddress(8080));

 

}

}

 

 

public class KaHandler extends SimpleChannelUpstreamHandler {

 

private static Logger log = Logger.getLogger(PaHandler.class);

 

@Override

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

try {

KaMessage req = (KaMessage) e.getMessage();

log.info("messageReceived: " + req);

KaRes res = new KaRes();

e.getChannel().write(res);

}catch(Exception ee) {

ee.printStackTrace();

}

}

}

 

三、客户端代码

 

public class ServerBoot {

 

public static void main(String[] args) {

// TODO Auto-generated method stub

 

ClientBootstrap bootstrap = new ClientBootstrap(

new NioClientSocketChannelFactory(

Executors.newCachedThreadPool(),

Executors.newCachedThreadPool()));

bootstrap.getPipeline().addLast("encoder", new KaEncoder());

bootstrap.getPipeline().addLast("decoder", new KaDecoder());

bootstrap.getPipeline().addLast("handler", new KaHandler());

ChannelFuture future = bootstrap.connect(new InetSocketAddress("127.0.0.1", 8080));

 

future.awaitUninterruptibly();

Channel channel = future.getChannel();

KaReq req = new KaReq();

 

future = channel.write(req);

future.awaitUninterruptibly();

 

 

 

 

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用 Netty 的 ChannelHandler 将二进制写入到 Netty 的通道中。具体来说,可以实现自定义的 ChannelInboundHandler,并在其中重写 channelRead() 方法。该方法会在每次有新数据到达时被调用,可以在其中处理二进制数据。 示例代码如下: ``` public class BinaryStreamHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf in = (ByteBuf) msg; try { while (in.isReadable()) { System.out.print((char) in.readByte()); System.out.flush(); } } finally { ReferenceCountUtil.release(msg); } } } ``` 然后,你可以在创建 Netty 服务器或客户端的时候,将该 ChannelHandler 添加到 ChannelPipeline 中。这样,每次有数据到达时,channelRead() 方法就会被调用,从而处理二进制数据。 需要注意的是,在使用完二进制数据后,一定要调用 ByteBuf 的 release() 方法释放缓存。如果不进行释放,可能会导致内存泄漏。 ### 回答2: 在Java代码中将二进制发送到Netty需要以下步骤: 1. 创建一个Netty的客户端或者服务器,并设置相关的配置,例如端口号和IP地址等。 2. 创建一个`ChannelPipeline`,它是Netty应用程序中处理输入和输出数据的处理器链。通过往`ChannelPipeline`中添加处理器,可以实现编码和解码、数据换、以及其他自定义的业务逻辑等。 3. 在`ChannelPipeline`中添加编码器,用于将二进制换成可发送的消息。Netty提供了多个编码器,例如`LengthFieldPrepender`和`ObjectEncoder`等,可以根据自己的需求选择适合的编码器。 4. 将待发送的二进制封装成消息对象,并将其写入`ChannelPipeline`中,以便通过网络发送。可以使用Netty提供的`ByteBuf`类来表示二进制数据,并添加到消息对象中。 5. 调用`Channel`的`writeAndFlush()`方法将消息对象发送出去。`writeAndFlush()`方法是一个异步操作,它会将消息写入底层的TCP缓冲区并发送出去,不会阻塞当前线程。 以下是一个简单的示例代码: ```java // 创建一个ByteBuf来表示二进制数据 ByteBuf buffer = Unpooled.buffer(); // 向ByteBuf中写入二进制数据 buffer.writeBytes(data); // 创建一个消息对象,并将ByteBuf添加到消息对象中 Message message = new Message(); message.setData(buffer); // 将消息对象写入ChannelPipeline并发送 channel.writeAndFlush(message); ``` 在上述示例中,`data`是待发送的二进制数据,`Message`是自定义的消息对象。将二进制数据封装成消息对象后,通过`channel.writeAndFlush()`方法将消息发送出去。 需要注意的是,在实际使用中,还需要根据业务需求处理接收到的数据和设置相应的异常处理逻辑。此外,还需要在应用程序退出时关闭Netty的客户端或服务器。 ### 回答3: 要将Java代码的二进制发送到Netty中,可以按照以下步骤进行: 1. 创建一个新的Netty客户端或服务器端。 2. 在Netty中,使用`ByteBuf`作为二进制数据的容器。使用`ByteBuf`的`writeBytes()`方法将Java代码的二进制写入到`ByteBuf`中。 3. 将`ByteBuf`发送给远程服务器或客户端。如果你是客户端,可以通过`Channel`的`writeAndFlush()`方法将`ByteBuf`发送给服务器。如果你是服务器,可以在接收到客户端连接的事件中,通过`ChannelHandlerContext`的`writeAndFlush()`方法将`ByteBuf`发送给客户端。 4. 在接收方,可以通过设置Netty的ChannelPipeline来处理接收到的数据。添加一个自定义的`ChannelInboundHandlerAdapter`,重写`channelRead()`方法来处理接收到的数据。 5. 在重写的`channelRead()`方法中,可以使用`ByteBuf`的`readBytes()`方法读取二进制数据。根据数据的格式和协议二进制数据换为需要的数据类型进行处理。 通过以上步骤,你就可以将Java代码的二进制发送到Netty并进行处理了。请注意,在实际应用中,你可能需要根据具体的需求和协议来进行适当地定制和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值