基于maven的构建环境:(pom.xml添加netty依赖)
io.netty
netty-all
4.1.32.Final
服务构建主类:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* @Author: geyingke
* @Date: 2020/7/20
* @Class: NettyServer
* @Discription: TODO
**/
public class NettyServer {
private Logger logger = LogManager.getLogger(NettyServer.class);
private final int port;
public NettyServer(int port) {
this.port = port;
}
public void start() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap
.group(bossGroup, group)
.channel(NioServerSocketChannel.class)
.localAddress(port)
//设置server初始化类,在初始化是判断响应的协议,分配到不同的ChannelHandler
.childHandler(new NettyServerInitializer());
ChannelFuture channelFuture = serverBootstrap.bind().sync();
logger.info(String.format("Netty server started!!!! port: %d", port));
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
group.shutdownGracefully().sync();
bossGroup.shutdownGracefully().sync();
} finally {
group.shutdownGracefully().sync();
bossGroup.shutdownGracefully().sync();
}
}
}
server初始化类
- 在初始化时,如果要兼容处理socket请求,socket的处Handler和相应的编码器必须在初始化的时候完成。目前仍在研究如何在一个handler处理两种类型的协议。
- 如果socket和websocket的Handler处理类不分开处理,websocket的捂手连接不能正常完成,目前正在寻找原因
- 当前实现tcp的粘包解决方案不使用netty提供的三种解决方案,连接方为c++程序,无包头标记码,因此循环截取bytebuff中的byte数组信息
import com.galaxyeye.icservice.im.parser.SocketUtils;
import com.galaxyeye.icservice.im.socket.NettySocketHandler;
import com.galaxyeye.icservice.im.webSocket.WebSocketHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import java.lang.invoke.MethodHandles;
import java.util.List;
/**
* @Author: geyingke
* @Date: 2020/7/21
* @Class: NettyServerInitializer
* @Discription: TODO
**/
@Component
public class NettyServerInitializer extends ChannelInitializer {
private Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//channel初始化
socketChannel.pipeline().addLast(new IdleStateHandler(60 * 2, 0, 0));
/**
* 注意:
* 1、netty兼容socket和websocket时,socket的响应处理必须在初始化时完成,否则socket消息后续处理失败
* 2、SocketParser用户鉴别websocket和socket,和socket消息粘包
* 3、如果同时兼容websocket和socket,socket消息的解码和编码需要在消息处理中进行,在pipeline后添加编码和解码器
*/
socketChannel.pipeline().addLast("SocketParser", new SocketParser());
socketChannel.pipeline().addLast(new NettySocketHandler());
}
private class SocketParser extends ByteToMessageDecoder {
/**
* WebSocket握手的协议前缀
*/
private static final String WEBSOCKET_PREFIX = "GET /";
private final Integer BASE_LENGTH = 14;
int beginIndex = 0;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List