Netty中Marshalling编解码自定义栈应用

本文介绍了一个基于 Netty 的 Java 项目,实现了客户端与服务端之间的心跳交互及登录验证过程。项目中详细定义了消息类型、消息结构,并通过 Marshalling 编码解码实现了复杂的对象传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工程结构图如下:
[img]http://dl2.iteye.com/upload/attachment/0113/9693/af21c27e-8e3f-3ef8-9114-84a9e4caf424.jpg[/img]

NettyConstant.java文件内容如下:

package com.shihuan.netty.protocol;

public final class NettyConstant {

public static final String REMOTEIP = "127.0.0.1";
public static final int PORT = 8080;
public static final int LOCAL_PORT = 12088;
public static final String LOCALIP = "127.0.0.1";

}


MessageType.java文件内容如下:

package com.shihuan.netty.protocol;

public enum MessageType {

SERVICE_REQ((byte) 0), SERVICE_RESP((byte) 1), ONE_WAY((byte) 2), LOGIN_REQ((byte) 3), LOGIN_RESP((byte) 4), HEARTBEAT_REQ((byte) 5), HEARTBEAT_RESP((byte) 6);

private byte value;

private MessageType(byte value) {
this.value = value;
}

public byte value() {
return this.value;
}

}


Header.java文件内容如下:

package com.shihuan.netty.protocol.struct;

import java.util.HashMap;
import java.util.Map;

public final class Header {

private int crcCode = 0xabef0101;

private int length; // 消息长度

private long sessionID; // 会话ID

private byte type; // 消息类型

private byte priority; // 消息优先级

private Map<String, Object> attachment = new HashMap<String, Object>(); // 附件

public final int getCrcCode() {
return crcCode;
}

public final void setCrcCode(int crcCode) {
this.crcCode = crcCode;
}

public final int getLength() {
return length;
}

public final void setLength(int length) {
this.length = length;
}

public final long getSessionID() {
return sessionID;
}

public final void setSessionID(long sessionID) {
this.sessionID = sessionID;
}

public final byte getType() {
return type;
}

public final void setType(byte type) {
this.type = type;
}

public final byte getPriority() {
return priority;
}

public final void setPriority(byte priority) {
this.priority = priority;
}

public final Map<String, Object> getAttachment() {
return attachment;
}

public final void setAttachment(Map<String, Object> attachment) {
this.attachment = attachment;
}

/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Header [crcCode=" + crcCode + ", length=" + length
+ ", sessionID=" + sessionID + ", type=" + type + ", priority="
+ priority + ", attachment=" + attachment + "]";
}

}


NettyMessage.java文件内容如下:

package com.shihuan.netty.protocol.struct;

public final class NettyMessage {

private Header header; //消息头

private Object body; //消息体

public final Header getHeader() {
return header;
}

public final void setHeader(Header header) {
this.header = header;
}

public final Object getBody() {
return body;
}

public final void setBody(Object body) {
this.body = body;
}

/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "NettyMessage [header=" + header + "]";
}

}


ChannelBufferByteInput.java文件内容如下:

package com.shihuan.netty.protocol.codec;

import io.netty.buffer.ByteBuf;

import java.io.IOException;

import org.jboss.marshalling.ByteInput;

class ChannelBufferByteInput implements ByteInput {

private final ByteBuf buffer;

public ChannelBufferByteInput(ByteBuf buffer) {
this.buffer = buffer;
}

@Override
public void close() throws IOException {

}

@Override
public int available() throws IOException {
return buffer.readableBytes();
}

@Override
public int read() throws IOException {
if (buffer.isReadable()) {
return buffer.readByte() & 0xff;
}
return -1;
}

@Override
public int read(byte[] array) throws IOException {
return read(array, 0, array.length);
}

@Override
public int read(byte[] dst, int dstIndex, int length) throws IOException {
int available = available();
if (available == 0) {
return -1;
}

length = Math.min(available, length);
buffer.readBytes(dst, dstIndex, length);
return length;
}

@Override
public long skip(long bytes) throws IOException {
int readable = buffer.readableBytes();
if (readable < bytes) {
bytes = readable;
}
buffer.readerIndex((int) (buffer.readerIndex() + bytes));
return bytes;
}

}


ChannelBufferByteOutput.java文件内容如下:

package com.shihuan.netty.protocol.codec;

import io.netty.buffer.ByteBuf;

import java.io.IOException;

import org.jboss.marshalling.ByteOutput;

class ChannelBufferByteOutput implements ByteOutput {

private final ByteBuf buffer;

/**
* Create a new instance which use the given {@link ByteBuf}
*/
public ChannelBufferByteOutput(ByteBuf buffer) {
this.buffer = buffer;
}

@Override
public void close() throws IOException {

}

@Override
public void flush() throws IOException {

}

@Override
public void write(int b) throws IOException {
buffer.writeByte(b);
}

@Override
public void write(byte[] bytes) throws IOException {
buffer.writeBytes(bytes);
}

@Override
public void write(byte[] bytes, int srcIndex, int length) throws IOException {
buffer.writeBytes(bytes, srcIndex, length);
}

/**
* Return the {@link ByteBuf} which contains the written content
*/
ByteBuf getBuffer() {
return buffer;
}

}


MarshallingCodecFactory.java文件内容如下:

package com.shihuan.netty.protocol.codec;

import java.io.IOException;

import org.jboss.marshalling.Marshaller;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;
import org.jboss.marshalling.Unmarshaller;

public final class MarshallingCodecFactory {

/**
* 创建Jboss Marshaller
* @throws IOException
*/
protected static Marshaller buildMarshalling() throws IOException {
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
Marshaller marshaller = marshallerFactory.createMarshaller(configuration);
return marshaller;
}

/**
* 创建Jboss Unmarshaller
* @throws IOException
*/
protected static Unmarshaller buildUnMarshalling() throws IOException {
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
final Unmarshaller unmarshaller = marshallerFactory.createUnmarshaller(configuration);
return unmarshaller;
}

}


MarshallingDecoder.java文件内容如下:

package com.shihuan.netty.protocol.codec;

import io.netty.buffer.ByteBuf;

import java.io.IOException;

import org.jboss.marshalling.ByteInput;
import org.jboss.marshalling.Unmarshaller;

public class MarshallingDecoder {

private final Unmarshaller unmarshaller;

/**
* Creates a new decoder whose maximum object size is {@code 1048576} bytes.
* If the size of the received object is greater than {@code 1048576} bytes,
* a {@link StreamCorruptedException} will be raised.
*
* @throws IOException
*
*/
public MarshallingDecoder() throws IOException {
unmarshaller = MarshallingCodecFactory.buildUnMarshalling();
}

protected Object decode(ByteBuf in) throws Exception {
int objectSize = in.readInt();
ByteBuf buf = in.slice(in.readerIndex(), objectSize);
ByteInput input = new ChannelBufferByteInput(buf);
try {
unmarshaller.start(input);
Object obj = unmarshaller.readObject();
unmarshaller.finish();
in.readerIndex(in.readerIndex() + objectSize);
return obj;
} finally {
unmarshaller.close();
}
}

}


MarshallingEncoder.java文件内容如下:

package com.shihuan.netty.protocol.codec;

import java.io.IOException;

import org.jboss.marshalling.Marshaller;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;

@Sharable
public class MarshallingEncoder {

private static final byte[] LENGTH_PLACEHOLDER = new byte[4];
Marshaller marshaller;

public MarshallingEncoder() throws IOException {
marshaller = MarshallingCodecFactory.buildMarshalling();
}

protected void encode(Object msg, ByteBuf out) throws Exception {
try {
int lengthPos = out.writerIndex();
out.writeBytes(LENGTH_PLACEHOLDER);
ChannelBufferByteOutput output = new ChannelBufferByteOutput(out);
marshaller.start(output);
marshaller.writeObject(msg);
marshaller.finish();
out.setInt(lengthPos, out.writerIndex() - lengthPos - 4);
} finally {
marshaller.close();
}
}

}


NettyMessageDecoder.java文件内容如下:

package com.shihuan.netty.protocol.codec;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.shihuan.netty.protocol.struct.Header;
import com.shihuan.netty.protocol.struct.NettyMessage;

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

public class NettyMessageDecoder extends LengthFieldBasedFrameDecoder {

MarshallingDecoder marshallingDecoder;

public NettyMessageDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) throws IOException {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
marshallingDecoder = new MarshallingDecoder();
}

@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, in);
if (frame == null) {
return null;
}

NettyMessage message = new NettyMessage();
Header header = new Header();
header.setCrcCode(frame.readInt());
header.setLength(frame.readInt());
header.setSessionID(frame.readLong());
header.setType(frame.readByte());
header.setPriority(frame.readByte());

int size = frame.readInt();
if (size > 0) {
Map<String, Object> attch = new HashMap<String, Object>(size);
int keySize = 0;
byte[] keyArray = null;
String key = null;
for (int i = 0; i < size; i++) {
keySize = frame.readInt();
keyArray = new byte[keySize];
frame.readBytes(keyArray);
key = new String(keyArray, "UTF-8");
attch.put(key, marshallingDecoder.decode(frame));
}
keyArray = null;
key = null;
header.setAttachment(attch);
}
if (frame.readableBytes() > 4) {
message.setBody(marshallingDecoder.decode(frame));
}
message.setHeader(header);
return message;
}

}


NettyMessageEncoder.java文件内容如下:

package com.shihuan.netty.protocol.codec;

import java.io.IOException;
import java.util.Map;

import com.shihuan.netty.protocol.struct.NettyMessage;

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

public final class NettyMessageEncoder extends MessageToByteEncoder<NettyMessage> {

MarshallingEncoder marshallingEncoder;

public NettyMessageEncoder() throws IOException {
this.marshallingEncoder = new MarshallingEncoder();
}

@Override
protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf sendBuf) throws Exception {
if (msg == null || msg.getHeader() == null) {
throw new Exception("The encode message is null");
}
sendBuf.writeInt((msg.getHeader().getCrcCode()));
sendBuf.writeInt((msg.getHeader().getLength()));
sendBuf.writeLong((msg.getHeader().getSessionID()));
sendBuf.writeByte((msg.getHeader().getType()));
sendBuf.writeByte((msg.getHeader().getPriority()));
sendBuf.writeInt((msg.getHeader().getAttachment().size()));
String key = null;
byte[] keyArray = null;
Object value = null;
for (Map.Entry<String, Object> param : msg.getHeader().getAttachment().entrySet()) {
key = param.getKey();
keyArray = key.getBytes("UTF-8");
sendBuf.writeInt(keyArray.length);
sendBuf.writeBytes(keyArray);
value = param.getValue();
marshallingEncoder.encode(value, sendBuf);
}
key = null;
keyArray = null;
value = null;
if (msg.getBody() != null) {
marshallingEncoder.encode(msg.getBody(), sendBuf);
} else {
sendBuf.writeInt(0);
}
sendBuf.setInt(4, sendBuf.readableBytes()-8);
}

}


HeartBeatRespHandler.java文件内容如下:

package com.shihuan.netty.protocol.server;

import com.shihuan.netty.protocol.MessageType;
import com.shihuan.netty.protocol.struct.Header;
import com.shihuan.netty.protocol.struct.NettyMessage;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

public class HeartBeatRespHandler extends ChannelHandlerAdapter {

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessage message = (NettyMessage) msg;
// 返回心跳应答消息
if (message.getHeader()!=null && message.getHeader().getType()==MessageType.HEARTBEAT_REQ.value()) {
System.out.println("Receive client heart beat message : ---> " + message);
NettyMessage heartBeat = buildHeatBeat();
System.out.println("Send heart beat response message to client : ---> " + heartBeat);
ctx.writeAndFlush(heartBeat);
} else
ctx.fireChannelRead(msg);
}

private NettyMessage buildHeatBeat() {
NettyMessage message = new NettyMessage();
Header header = new Header();
header.setType(MessageType.HEARTBEAT_RESP.value());
message.setHeader(header);
return message;
}

}


LoginAuthRespHandler.java文件内容如下:

package com.shihuan.netty.protocol.server;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.shihuan.netty.protocol.MessageType;
import com.shihuan.netty.protocol.struct.Header;
import com.shihuan.netty.protocol.struct.NettyMessage;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

public class LoginAuthRespHandler extends ChannelHandlerAdapter {

private Map<String, Boolean> nodeCheck = new ConcurrentHashMap<String, Boolean>();
private String[] whitekList = { "127.0.0.1", "192.168.1.104" };

/**
* Calls {@link ChannelHandlerContext#fireChannelRead(Object)} to forward to
* the next {@link ChannelHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessage message = (NettyMessage) msg;

// 如果是握手请求消息,处理,其它消息透传
if (message.getHeader()!=null && message.getHeader().getType()==MessageType.LOGIN_REQ.value()) {
String nodeIndex = ctx.channel().remoteAddress().toString();
NettyMessage loginResp = null;
// 重复登陆,拒绝
if (nodeCheck.containsKey(nodeIndex)) {
loginResp = buildResponse((byte) -1);
} else {
InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
String ip = address.getAddress().getHostAddress();
boolean isOK = false;
for (String WIP : whitekList) {
if (WIP.equals(ip)) {
isOK = true;
break;
}
}
loginResp = isOK ? buildResponse((byte) 0) : buildResponse((byte) -1);
if (isOK) {
nodeCheck.put(nodeIndex, true);
}
}
System.out.println("The login response is : " + loginResp + " body [" + loginResp.getBody() + "]");
ctx.writeAndFlush(loginResp);
} else {
ctx.fireChannelRead(msg);
}
}

private NettyMessage buildResponse(byte result) {
NettyMessage message = new NettyMessage();
Header header = new Header();
header.setType(MessageType.LOGIN_RESP.value());
message.setHeader(header);
message.setBody(result);
return message;
}

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
nodeCheck.remove(ctx.channel().remoteAddress().toString()); // 删除缓存
ctx.close();
ctx.fireExceptionCaught(cause);
}

}


NettyServer.java文件内容如下:

package com.shihuan.netty.protocol.server;

import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;

import java.io.IOException;

import com.shihuan.netty.protocol.NettyConstant;
import com.shihuan.netty.protocol.codec.NettyMessageDecoder;
import com.shihuan.netty.protocol.codec.NettyMessageEncoder;

public class NettyServer {

public void bind() throws Exception {
// 配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws IOException {
ch.pipeline().addLast(new NettyMessageDecoder(1024 * 1024, 4, 4));
ch.pipeline().addLast(new NettyMessageEncoder());
ch.pipeline().addLast("readTimeoutHandler", new ReadTimeoutHandler(50));
ch.pipeline().addLast(new LoginAuthRespHandler());
ch.pipeline().addLast("HeartBeatHandler", new HeartBeatRespHandler());
}
});

// 绑定端口,同步等待成功
ChannelFuture f = b.bind(NettyConstant.REMOTEIP, NettyConstant.PORT).sync();
System.out.println("Netty server start ok : " + (NettyConstant.REMOTEIP + " : " + NettyConstant.PORT));
// 等待服务端监听端口关闭
f.channel().closeFuture().sync();


// 绑定端口,同步等待成功
//b.bind(NettyConstant.REMOTEIP, NettyConstant.PORT).sync();
//System.out.println("Netty server start ok : " + (NettyConstant.REMOTEIP + " : " + NettyConstant.PORT));
} finally {
// 优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}

public static void main(String[] args) throws Exception {
new NettyServer().bind();
}

}


HeartBeatReqHandler.java文件内容如下:

package com.shihuan.netty.protocol.client;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import com.shihuan.netty.protocol.MessageType;
import com.shihuan.netty.protocol.struct.Header;
import com.shihuan.netty.protocol.struct.NettyMessage;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

public class HeartBeatReqHandler extends ChannelHandlerAdapter {

private volatile ScheduledFuture<?> heartBeat;

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessage message = (NettyMessage) msg;
// 握手成功,主动发送心跳消息
if (message.getHeader()!=null && message.getHeader().getType()==MessageType.LOGIN_RESP.value()) {
heartBeat = ctx.executor().scheduleAtFixedRate(new HeartBeatReqHandler.HeartBeatTask(ctx), 0, 5000, TimeUnit.MILLISECONDS);
} else if (message.getHeader()!=null && message.getHeader().getType()==MessageType.HEARTBEAT_RESP.value()) {
System.out.println("Client receive server heart beat message : ---> " + message);
} else {
ctx.fireChannelRead(msg);
}
}

private class HeartBeatTask implements Runnable {
private final ChannelHandlerContext ctx;

public HeartBeatTask(final ChannelHandlerContext ctx) {
this.ctx = ctx;
}

@Override
public void run() {
NettyMessage heatBeat = buildHeatBeat();
System.out.println("Client send heart beat messsage to server : ---> " + heatBeat);
ctx.writeAndFlush(heatBeat);
}

private NettyMessage buildHeatBeat() {
NettyMessage message = new NettyMessage();
Header header = new Header();
header.setType(MessageType.HEARTBEAT_REQ.value());
message.setHeader(header);
return message;
}
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
if (heartBeat != null) {
heartBeat.cancel(true);
heartBeat = null;
}
ctx.fireExceptionCaught(cause);
}

}


LoginAuthReqHandler.java文件内容如下:

package com.shihuan.netty.protocol.client;

import com.shihuan.netty.protocol.MessageType;
import com.shihuan.netty.protocol.struct.Header;
import com.shihuan.netty.protocol.struct.NettyMessage;

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

public class LoginAuthReqHandler extends ChannelHandlerAdapter {

/**
* Calls {@link ChannelHandlerContext#fireChannelActive()} to forward to the
* next {@link ChannelHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(buildLoginReq());
}

/**
* Calls {@link ChannelHandlerContext#fireChannelRead(Object)} to forward to
* the next {@link ChannelHandler} in the {@link ChannelPipeline}.
*
* Sub-classes may override this method to change behavior.
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessage message = (NettyMessage) msg;

// 如果是握手应答消息,需要判断是否认证成功
if (message.getHeader()!=null && message.getHeader().getType()==MessageType.LOGIN_RESP.value()) {
byte loginResult = (byte) message.getBody();
if (loginResult != (byte) 0) {
// 握手失败,关闭连接
ctx.close();
} else {
System.out.println("Login is ok : " + message);
ctx.fireChannelRead(msg);
}
} else {
ctx.fireChannelRead(msg);
}
}

private NettyMessage buildLoginReq() {
NettyMessage message = new NettyMessage();
Header header = new Header();
header.setType(MessageType.LOGIN_REQ.value());
message.setHeader(header);
return message;
}

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.fireExceptionCaught(cause);
}

}


NettyClient.java文件内容如下:

package com.shihuan.netty.protocol.client;

import io.netty.bootstrap.Bootstrap;
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;
import io.netty.handler.timeout.ReadTimeoutHandler;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.shihuan.netty.protocol.NettyConstant;
import com.shihuan.netty.protocol.codec.NettyMessageDecoder;
import com.shihuan.netty.protocol.codec.NettyMessageEncoder;

public class NettyClient {

private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
EventLoopGroup group = new NioEventLoopGroup();

public void connect(int port, String host) throws Exception {
// 配置客户端NIO线程组
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyMessageDecoder(1024 * 1024, 4, 4));
ch.pipeline().addLast("MessageEncoder", new NettyMessageEncoder());
ch.pipeline().addLast("readTimeoutHandler", new ReadTimeoutHandler(50));
ch.pipeline().addLast("LoginAuthHandler", new LoginAuthReqHandler());
ch.pipeline().addLast("HeartBeatHandler", new HeartBeatReqHandler());
}
});
// 发起异步连接操作
ChannelFuture future = b.connect(new InetSocketAddress(host, port), new InetSocketAddress(NettyConstant.LOCALIP, NettyConstant.LOCAL_PORT)).sync();
future.channel().closeFuture().sync();
} finally {
// 所有资源释放完成之后,清空资源,再次发起重连操作
executor.execute(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
try {
connect(NettyConstant.PORT, NettyConstant.REMOTEIP); // 发起重连操作
} catch (Exception e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}

public static void main(String[] args) throws Exception {
new NettyClient().connect(NettyConstant.PORT, NettyConstant.REMOTEIP);
}

}



【注】: 附件中的protocolstack.rar文件是可运行的工程源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值