PBMessage 结构体
package com.road.message;
import io.netty.buffer.ByteBuf;
import java.nio.ByteBuffer;
import org.apache.mina.core.buffer.IoBuffer;
import com.google.protobuf.Message;
public class PBMessage {
private static final long serialVersionUID = 1L;
public static final short HDR_SIZE = 10;
public static final short HEADER = 0x71ab;
private short header = HEADER;
private short len;
private short code;
private int playerId;
private int byteLength;
private byte[] bytes;
private Message message; // Proto
private byte opCode = 0x2;
private Object myMsg;
public PBMessage() {
}
public PBMessage(Object myMsg) {
this.myMsg = myMsg;
}
public PBMessage(short code, byte[] bytes) {
this(code, -1);
this.bytes = bytes;
}
public PBMessage(short code) {
this(code, -1);
}
public PBMessage(short code, int playerId) {
this.code = code;
this.playerId = playerId;
}
public PBMessage(short code, Object myMsg) {
this.code = code;
this.myMsg = myMsg;
}
public PBMessage(short code, int playerId, Object myMsg) {
this.code = code;
this.playerId = playerId;
this.myMsg = myMsg;
}
public short getHeader() {
return header;
}
public short getLen() {
return len;
}
public void setLen(short len) {
this.len = len;
}
public short getCode() {
return code;
}
public void setCode(short code) {
this.code = code;
}
public int getPlayerId() {
return playerId;
}
public void setPlayerId(int playerId) {
this.playerId = playerId;
}
public byte[] getBytes() {
return bytes;
}
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
public void readHeader(ByteBuffer in) {
in.getShort();
len = in.getShort();
code = in.getShort();
playerId = in.getInt();
}
public void readHeader(IoBuffer in) {
in.getShort();
len = in.getShort();
code = in.getShort();
playerId = in.getInt();
}
public void readHeaderNetty(ByteBuf in) {
in.readShort();
len = in.readShort();
code = in.readShort();
playerId = in.readInt();
}
public void readHeader1(IoBuffer in) {
in.getShort();
len = in.getShort();
code = in.getShort();
playerId = in.getInt();
bytes = new byte[len - 10];
in.get(bytes, 0, bytes.length);
}
public void read(ByteBuf in) {
in.readShort();
len = in.readShort();
code = in.readShort();
playerId = in.readInt();
bytes = new byte[in.capacity() - 10];
in.readBytes(bytes);
}
public void writeHeader(int len, ByteBuffer out) {
out.putShort(HEADER);
out.putShort((short) len);
out.putShort(code);
out.putInt(playerId);
}
public void writeHeader(int len, IoBuffer out) {
out.putShort(HEADER);
out.putShort((short) len);
out.putShort(code);
out.putInt(playerId);
}
public void writeHeader(int len, ByteBuf out) {
out.writeShort(HEADER);
out.writeShort((short) len);
out.writeShort(code);
out.writeInt(playerId);
if (message != null) {
out.writeBytes(message.toByteArray());
}
else if (bytes != null) {
if (byteLength != 0) {
out.writeBytes(bytes, 0, byteLength);
} else {
out.writeBytes(bytes);
}
}
}
public void writeHeaderByte(int len, ByteBuf out) {
out.writeShort(HEADER);
out.writeShort((short) len);
out.writeShort(code);
out.writeInt(playerId);
if (bytes != null) {
out.writeBytes(bytes);
}
}
public void writeHeartbeat(int len, ByteBuf out) {
out.writeShort(HEADER);
out.writeShort((short) len);
out.writeShort(code);
out.writeInt(playerId);
}
public byte[] toByteArray() {
return bytes;
}
public short calcChecksum(byte[] data) {
int val = 0x77;
int i = 6;
int size = data.length;
while (i < size) {
val += (data[i++] & 0xFF);
}
return (short) (val & 0x7F7F);
}
public String headerToStr() {
StringBuilder sb = new StringBuilder();
sb.append("playerId : ").append(playerId);
sb.append(", code : ").append(Integer.toHexString(code));
sb.append(", len : ").append(len);
return sb.toString();
}
public String detailToStr() {
if (bytes == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(b + ", ");
}
return headerToStr() + ", content : [" + sb.toString() + "]";
}
public byte getOpCode() {
return opCode;
}
public void setOpCode(byte opCode) {
this.opCode = opCode;
}
public Object getMyMsg() {
return myMsg;
}
public void setMyMsg(Object myMsg) {
this.myMsg = myMsg;
}
public int getByteLength() {
return byteLength;
}
public void setByteLength(int byteLength) {
this.byteLength = byteLength;
}
@Override
public PBMessage clone() {
PBMessage clone = null;
try {
clone = (PBMessage) super.clone();
clone.setMessage(message);
return clone;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
server
package com.road.nettysocket;
import com.road.code.ProtoBufDecoderNew;
import com.road.code.ProtoBufEncoderNew;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer {
private static final EventLoopGroup bossGroup = new NioEventLoopGroup(4);
private static final EventLoopGroup workerGroup = new NioEventLoopGroup(4);
public void bind(int port)
{
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChildChannelHandler());
try {
ChannelFuture f = b.bind("127.0.0.1",port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally
{
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel>
{
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast("decoder", new ProtoBufDecoderNew());
channel.pipeline().addLast("encoder", new ProtoBufEncoderNew());
channel.pipeline().addLast(new ServerHandler());
}
}
public static void main(String[] args)
{
new NettyServer().bind(9500);
}
}
package com.road.nettysocket;
import com.road.message.PBMessage;
import com.road.snake.pb.PlayerDeadMsgProto.PlayerDeadMsg;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class ServerHandler extends SimpleChannelInboundHandler<PBMessage>{
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, PBMessage msg)
throws Exception {
PlayerDeadMsg req = PlayerDeadMsg.parseFrom(msg.toByteArray());
System.out.println("getDeadUserId=="+req.getDeadUserId());
System.out.println("KillUserId=="+req.getKillUserId());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("连接断开 : " + ctx.channel().remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("连接异常 : " + ctx.channel().remoteAddress() + " error : " + cause);
ctx.close();
}
}
package com.road.code;
import java.util.List;
import com.road.message.PBMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
public class ProtoBufDecoderNew extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() < PBMessage.HDR_SIZE) {
return;
}
ByteBuf byteBuf = in.slice();
short headerFlag = byteBuf.readShort();
if (PBMessage.HEADER != headerFlag) {
byteBuf.readShort();
return;
}
int lenght = byteBuf.readShort();
if (lenght <= 0 || lenght >= Short.MAX_VALUE) {
System.out.println("Message Length Invalid Length = " + lenght + ", drop this Message.");
return;
}
if (lenght > in.readableBytes()) {
return;
}
PBMessage pkg = new PBMessage();
pkg.readHeaderNetty(in);
int bodyLen = lenght - PBMessage.HDR_SIZE;
if (bodyLen > 0) {
byte[] bytes = new byte[bodyLen];
in.readBytes(bytes, 0, bodyLen);
pkg.setBytes(bytes);
}
out.add(pkg);
}
}
package com.road.code;
import java.io.IOException;
import java.util.List;
import com.google.protobuf.Message;
import com.road.message.PBMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
public class ProtoBufEncoderNew extends MessageToMessageEncoder<PBMessage> {
@Override
protected void encode(ChannelHandlerContext ctx, PBMessage msg, List<Object> out) throws Exception {
Object object = msg.getMyMsg();
if (object != null && msg.getMyMsg() instanceof PBMessageBuffer) {
PBMessageBuffer messageBuffer = (PBMessageBuffer) msg.getMyMsg();
for (PBMessage message : messageBuffer) {
encodeMessage(ctx, message, out);
}
} else {
encodeMessage(ctx, msg, out);
}
}
private void encodeMessage(ChannelHandlerContext ctx, PBMessage message, List<Object> out) throws IOException {
Message pbMessage = message.getMessage();
int size = PBMessage.HDR_SIZE;
if (pbMessage != null) {
size = PBMessage.HDR_SIZE + pbMessage.getSerializedSize();
} else {
byte[] bytes = message.getBytes();
if (bytes != null) {
size = PBMessage.HDR_SIZE + bytes.length;
}
}
if (size > Short.MAX_VALUE) {
return;
}
ByteBuf buffer = ctx.alloc().buffer(size);
message.writeHeader(size, buffer);
out.add(buffer);
}
}
package com.road.code;
import java.util.ArrayList;
import com.road.message.PBMessage;
public class PBMessageBuffer extends ArrayList<PBMessage> {
private static final long serialVersionUID = 1L;
}
package com.road.code;
import com.google.protobuf.AbstractMessage.Builder;
import com.google.protobuf.Message;
import com.road.message.PBMessage;
/**
* 鏉堝懎濮猾锟�
*/
public class MessageUtil {
/**
* 濞戝牊浼呴崚娑樼紦
*
* @param code
* @param messageBuilder
* @return
*/
public static PBMessage buildMessage(short code, Builder<?> messageBuilder) {
return buildMessage(code, messageBuilder.build());
}
/**
* 濞戝牊浼呴崚娑樼紦
*
* @param code
* @param messageBuilder
* @return
*/
public static PBMessage buildMessage(short code, Message message) {
PBMessage response = new PBMessage(code, -1);
response.setMessage(message);
return response;
}
public static PBMessage buildMessageByte(short code, byte[] data) {
PBMessage response = new PBMessage(code, -1);
response.setBytes(data);
return response;
}
public static PBMessage buildMessageByte(short code, int userId, byte[] data) {
PBMessage response = new PBMessage(code, userId);
response.setBytes(data);
return response;
}
public static PBMessage buildMessageByte(short code, int userId, int byteLength, byte[] data) {
PBMessage response = new PBMessage(code, userId);
response.setByteLength(byteLength);
response.setBytes(data);
return response;
}
/**
* 濞戝牊浼呴崚娑樼紦
*
* @param code
* @param client
* @param messageBuilder
* @return
*/
public static PBMessage buildMessage(short code, int client, Builder<?> messageBuilder) {
PBMessage response = new PBMessage(code, client);
response.setMessage(messageBuilder.build());
return response;
}
/**
* 濞戝牊浼呴崚娑樼紦
*
* @param code
* @param client
* @return
*/
public static PBMessage buildMessage(short code, int client) {
PBMessage message = new PBMessage(code, client);
return message;
}
/**
* 濞戝牊浼呴崚娑樼紦
*
* @param code
* @param messageBuilder
* @return
*/
public static PBMessage buildMessage(short code, Object object) {
PBMessage response = new PBMessage(code, object);
return response;
}
}
package com.road.nettysocket;
import com.road.code.MessageUtil;
import com.road.code.ProtoBufDecoderNew;
import com.road.code.ProtoBufEncoderNew;
import com.road.message.PBMessage;
import com.road.snake.pb.PlayerDeadMsgProto.PlayerDeadMsg;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class NettyClient {
public static Channel channel;
public void connect(int port,String host)
{
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChildChannelHandler());
b.option(ChannelOption.SO_KEEPALIVE, true);
try {
ChannelFuture future =b.connect(host, port).sync();
channel = future.channel();
//channel.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally
{
//group.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel>
{
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast("decoder", new ProtoBufDecoderNew());
channel.pipeline().addLast("encoder", new ProtoBufEncoderNew());
channel.pipeline().addLast(new ClientHandler());
}
}
public static void sendMsg(String msg) throws Exception {
if(channel!=null){
channel.writeAndFlush(msg).sync();
}else{
System.out.println("消息发送失败,连接尚未建立!");
}
}
public static void main(String[] args)
{
new NettyClient().connect(9500, "127.0.0.1");
PlayerDeadMsg.Builder msg = PlayerDeadMsg.newBuilder();
msg.setDeadUserId(100);
msg.setKillUserId(200);
PBMessage message = MessageUtil.buildMessage((short)125, msg);
for (int i = 0; i < 100000; i++) {
try {
sendPacket(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void sendPacket(PBMessage message) {
if (!channel.isActive()) {
return;
}
message.setPlayerId(522);
int size = message.getMessage().getSerializedSize() + 10;
ByteBuf respBuffer = Unpooled.buffer(size);
message.writeHeader(size, respBuffer);
try {
channel.writeAndFlush(message).sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.road.nettysocket;
import com.road.message.PBMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class ClientHandler extends SimpleChannelInboundHandler<PBMessage>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, PBMessage msg)
throws Exception {
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("连接断开 : " + ctx.channel().remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("连接异常 : " + ctx.channel().remoteAddress() + " error : " + cause);
}
}
重要的地方:
channel.pipeline().addLast("decoder", new ProtoBufDecoderNew());
channel.pipeline().addLast("encoder", new ProtoBufEncoderNew());