一个简单的Netty服务 接收什么信息就回复什么信息
总目录
Netty 5.x 2.自定义编解码器
当前目录
Maven依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
创建服务并绑定端口 以及 编解码器
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class Server extends Thread{
private int port = -1;
public Server(int port) {
this.port = port;
}
@Override
public void run() {
bind(port);
}
private void bind(int port) {
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup work = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
try {
bootstrap.group(boss, work)
.channel(NioServerSocketChannel.class)//注册factory
.childHandler(new ChannelInitializer<Channel>() {//注册piepline
@Override
protected void initChannel(Channel sc) throws Exception {//初始化连接
sc.pipeline()
.addLast(new Decode()) //添加自定义解码器
.addLast(new Encode()) //添加自定义编码器
.addLast(new ServerHandle()); //添加处理网络io类
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.TCP_NODELAY, true)//TCP无掩饰
.childOption(ChannelOption.SO_KEEPALIVE,true);//清除死连接,维持活跃的
ChannelFuture future = bootstrap.bind(port);
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
boss.shutdownGracefully();
work.shutdownGracefully();
}
}
}
解码器
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
public class Decode extends ByteToMessageDecoder {
private static final int MIN_LENGTH = 2+2+2; //数据内容为空时最小长度 即(协议头、版本号、消息长度(长度=0时消息最短))
private static final int MAX_LENGTH = 2048; //约定数据最大长度(防止socket字节流攻击)
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
try {
if(in.readableBytes()<MIN_LENGTH) {//可读取字节数少于最小长度
return;
}
if(in.readableBytes() > MAX_LENGTH){//可读字节数大于约定最大长度
in.skipBytes(in.readableBytes());
return;
}
while(true) {
in.markReaderIndex();
if(in.readShort() == Message.TAG){//寻找协议头
if(in.readShort()==Message.VERSION) {
break;
}
}
in.resetReaderIndex();
in.readByte();
if(in.readableBytes() <= MIN_LENGTH){
return;
}
if(in.readableBytes() > MAX_LENGTH){
in.skipBytes(in.readableBytes());
return;
}
}
Message message = new Message();
int length = in.readInt();
message.setLENGTH(length);
byte[] data = new byte[length-8];
in.readBytes(data);
message.setDATA(new String(data,"ISO-8859-1"));
out.add(message);
}catch(Exception e) {
e.printStackTrace();
}
}
}
编码器
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class Encode extends MessageToByteEncoder<Message> {
@Override
protected void encode(ChannelHandlerContext ctx, Message message, ByteBuf out) throws Exception {
out.writeShort(Message.TAG);
out.writeShort(Message.VERSION);
out.writeBytes(message.getDATA().getBytes("ISO-8859-1"));
out.setShort(4, out.readableBytes()+2);
}
}
接收发送数据类
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class ServerHandle extends SimpleChannelInboundHandler<Message>{
@Override
protected void messageReceived(ChannelHandlerContext cx, Message message) throws Exception {
System.out.println(message);
cx.write(message);
cx.flush();
}
}
消息格式类(实体类/协议格式)
public class Message {
public final static short TAG = (short) 0xFEFD; //协议头(长度2字节)
public final static short VERSION = 0x0100; //版本号(长度2字节)
private int LENGTH; //消息长度(整个数据包长度,2字节)
private String DATA; //消息内容
public int getLENGTH() {
return LENGTH;
}
public void setLENGTH(int lENGTH) {
LENGTH = lENGTH;
}
public String getDATA() {
return DATA;
}
public void setDATA(String dATA) {
DATA = dATA;
}
@Override
public String toString() {
return "Message [TAG=" + TAG + ", VERSION=" + VERSION + ", LENGTH=" + LENGTH + ", DATA=" + DATA + "]";
}
}