1.版本:
springboot 1.5.20 +netty 4.1.35
2.依赖:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.35.Final</version>
</dependency>
3.yml配置
client:
ip: 127.0.0.1
port: 60009
我们创建的是nutty客户端,需要连接服务端;ip 、port为服务端ip和端口。
4.代码
public class Client {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private int port;
private String host;
private SocketChannel socketChannel;
private Thread thread;
public Client(int port, String host) {
this.host = host;
this.port = port;
start();
}
public boolean isConnected(){
return isConnect;
}
private boolean isConnect = true;
public void stop(){
try {
if (thread.isAlive()) {
thread.destroy();
}
}catch(Exception ex){
logger.error("关闭线程异常:" + ex.toString());
}
}
public void start() {
thread = new Thread(new Runnable() {
@Override
public void run() {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class)
// 保持连接
.option(ChannelOption.SO_KEEPALIVE, true)
// 有数据立即发送
.option(ChannelOption.TCP_NODELAY, true)
// 绑定处理group
.group(eventLoopGroup).remoteAddress(host, port)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 初始化编码器,解码器,处理器
socketChannel.pipeline().addLast(
new MessageDecoder(),
new MessageEncoder(),
new ClientHandler());
}
});
// 进行连接
ChannelFuture future;
try {
future = bootstrap.connect(host, port).sync();
// 判断是否连接成功
if (future.isSuccess()) {
// 得到管道,便于通信
socketChannel = (SocketChannel) future.channel();
isConnect = true;
logger.info("客户端开启成功...");
}
else{
logger.error("客户端开启失败...");
}
// 等待客户端链路关闭,就是由于这里会将线程阻塞,导致无法发送信息,所以我这里开了线程
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
logger.error("连接断开,退出!");
isConnect = false;
//优雅地退出,释放相关资源
eventLoopGroup.shutdownGracefully();
}
}
});
thread.start();
}
public void sendMessage(Object msg) {
if (socketChannel != null) {
if(msg instanceof String){
socketChannel.writeAndFlush(msg);
}
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ClientHandler extends ChannelInboundHandlerAdapter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info("消息:" + msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
logger.info("通道读取完毕!");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (null != cause) {
cause.printStackTrace();
}
if (null != ctx) {
ctx.close();
}
}
}
import com.cjwl.forward808.util.StringByteConvertUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class MessageDecoder extends ByteToMessageDecoder {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
//标记开始读取位置
in.markReaderIndex();
//判断协议类型
byte infoType = in.readByte();
//in.readableBytes()即为剩下的字节数
byte[] info = new byte[in.readableBytes()];
in.readBytes(info);
String msg = StringByteConvertUtil.bytesToHexString(info);
logger.info("Decode:" + msg);
//最后把你想要交由ServerHandler的数据添加进去,就可以了
out.add(msg);
}
}
import com.cjwl.forward808.util.StringByteConvertUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MessageEncoder extends MessageToByteEncoder<String> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception {
ByteBufOutputStream writer = new ByteBufOutputStream(out);
byte[] info = null;
if (!StringUtils.isBlank(msg)) {
logger.info("Encode:" + msg);
info = StringByteConvertUtil.hexStringToByte(msg);
writer.write(info);
}
}
}
5.使用示例
Client bootstrap808 = new Client(serverPort, serverIp);
/**
* 发送消息
*
*/
public void sendMsg(String message) throws Exception {
while (!bootstrap808.isConnected()){
bootstrap808.start();
if (!bootstrap808.isConnected()) {
Thread.sleep(1000*60);
}
}
bootstrap808.sendMessage(message);
}
public void sendMsg(byte[] msg) throws Exception {
bootstrap808.sendMessage(msg);
}