工作中用的: 解码器:LengthFiledBasedFrameDecoder+ChannelInboundHandlerAdapter 编码器:MessageToByteEncoder

pom.xml

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.38.Final</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.53</version>
        </dependency>
    </dependencies>

common

Decoder.java  // 解码器

package org.example.common;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

public class Decoder extends LengthFieldBasedFrameDecoder {
	public Decoder() {
		super(Integer.MAX_VALUE, 0, 4, -4, 0);
	}

	@Override
	protected Object decode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
		ByteBuf buffs = (ByteBuf) super.decode(ctx, buf);
		if (buffs == null) {
			return null;
		}
		try {
			int len = buffs.readInt();
			int msgId = buffs.readInt();

			// ByteBuf转byte[]
			byte[] bs = new byte[buffs.readableBytes()];
			buffs.readBytes(bs);

			String str = new String(bs);
			return new GameMessage(msgId, str);
		} finally {
			buffs.release();
		}
	}
}

Encoder.java // 编码器

package org.example.common;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

public class Encoder extends MessageToByteEncoder<byte[]> {
	@Override
	protected void encode(ChannelHandlerContext ctx, byte[] msg, ByteBuf out) throws Exception {
		out.writeBytes(msg);
	}
}

GameMessage.java // 消息体

package org.example.common;

import lombok.Data;
import lombok.ToString;

import java.io.Serializable;

@Data
@ToString
public class GameMessage implements Serializable {
	private static final long serialVersionUID = 1L;

	private int msgId;
	private String str;

	public GameMessage(int msgId, String str) {
		this.msgId = msgId;
		this.str = str;
	}
}

SendUtils.java

package org.example.common;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;

import java.nio.charset.StandardCharsets;

public class SendUtils {
	public static void sendMessage(Channel channel, GameMessage gameMessage) {
		try {
			byte[] bytes = gameMessage.getStr().getBytes(StandardCharsets.UTF_8);

			// 要发送的数据
			ByteBuf data = channel.alloc().buffer(8 + bytes.length);

			data.writeInt(8 + bytes.length);
			data.writeInt(gameMessage.getMsgId());
			data.writeBytes(bytes);

			channel.writeAndFlush(data);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

server

GameServer.java // 游戏服启动类

package org.example.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.example.common.Decoder;
import org.example.common.Encoder;


public class GameServer {
	public static void main(String[] args) {
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		EventLoopGroup workerGroup = new NioEventLoopGroup();

		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
					.option(ChannelOption.SO_BACKLOG, 10240)
					.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) // 使用内存池
					.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) // 使用内存池
					.childOption(ChannelOption.TCP_NODELAY, true)
					.childOption(ChannelOption.SO_KEEPALIVE, true)
					.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(128 * 1024, 256 * 1024))
					.childHandler(new ChannelInitializer<SocketChannel>() {

						@Override
						protected void initChannel(SocketChannel ch) throws Exception {
							ChannelPipeline p = ch.pipeline();
							p.addLast(new IdleStateHandler(5 * 60, 5 * 60, 0), new Decoder(), new Encoder(), new GatewayHandler());
						}
					});

			Channel channel = bootstrap.bind(3000).sync().channel();

			System.out.println("server start!!!");

			channel.closeFuture().sync();
		} catch (Exception e) {
			System.exit(1);
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}

	}
}

ClientSession.java

package org.example.server;

import io.netty.channel.Channel;
import lombok.Data;
import org.example.common.GameMessage;
import org.example.common.SendUtils;

@Data
public class ClientSession {
	private Channel channel;

	public ClientSession(Channel channel) {
		this.channel = channel;
	}

	public void parseAndDispatchMessage(GameMessage gameMessage) throws Exception {
		System.out.println( gameMessage.toString());

		sendMsg(gameMessage);
	}

	public void sendMsg(GameMessage gameMessage) {
		SendUtils.sendMessage(channel, gameMessage);
	}
}

GatewayHandler.java // 解码后,进入服务器处理函数

package org.example.server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import org.example.common.GameMessage;

public class GatewayHandler extends ChannelInboundHandlerAdapter {
	private ClientSession session;

	GatewayHandler() {

	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try {
			if (msg == null) {
				return;
			}
			GameMessage gameMessage = (GameMessage) msg;


			session.parseAndDispatchMessage(gameMessage);
		} finally {
			ReferenceCountUtil.refCnt(msg);
		}
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		session = new ClientSession(ctx.channel());
	}
}

client

Client.java

package org.example.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.example.common.Decoder;
import org.example.common.Encoder;

import java.net.InetSocketAddress;


public class Client {
	public Client(){

	}

	public void connect() throws Exception{
		Bootstrap bootstrap = new Bootstrap();
		EventLoopGroup workerGroup = new NioEventLoopGroup(1);
		bootstrap.group(workerGroup)
				.option(ChannelOption.SO_REUSEADDR, true)
				.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
				.channel(NioSocketChannel.class)
				.handler(new ChannelInitializer<>() {
					@Override
					protected void initChannel(Channel ch) throws Exception {
						ChannelPipeline p = ch.pipeline();
						p.addLast(new Decoder(), new Encoder(), new ClientHandler());
					}
				});

		bootstrap.connect((new InetSocketAddress("localhost", 3000))).sync();
	}
}

ClientApp.java

package org.example.client;

public class ClientApp {
	public static void main(String[] args) throws Exception {
		Client client = new Client();
		client.connect();
	}
}

ClientHandler.java // 解码后,进入客户端处理函数

package org.example.client;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.example.common.GameMessage;

public class ClientHandler extends ChannelInboundHandlerAdapter {
	private ServerSession session;

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		session = new ServerSession(ctx.channel());

		session.sendMsg(new GameMessage(1, "我是中国人"));
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		GameMessage gameMessage = (GameMessage) msg;

		System.out.println(gameMessage.toString());

	}
}

ServerSession.java

package org.example.client;

import io.netty.channel.Channel;
import org.example.common.GameMessage;
import org.example.common.SendUtils;

public class ServerSession {
	private Channel channel;

	public ServerSession(Channel channel) {
		this.channel = channel;
	}

	public void sendMsg(GameMessage gameMessage) {
		SendUtils.sendMessage(channel, gameMessage);
	}
}

运行结果:

 总结:

这是工作中最常用的一种编解码器。数据包格式如下:

4字节 // 记录总长度

4字节 // 记录msgId

body // 消息题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值