public class WSServer {
public static void main(String[] args) throws Exception{
EventLoopGroup mainGroup = new NioEventLoopGroup();
EventLoopGroup subGroup = new NioEventLoopGroup();
try {
ServerBootstrap server = new ServerBootstrap();
server.group(mainGroup, subGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WSServerInitializer());
ChannelFuture future = server.bind(8088).sync();
future.channel().closeFuture().sync();
} finally {
mainGroup.shutdownGracefully();
subGroup.shutdownGracefully();
}
}
}
public class WSServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// websocket 基于http协议, 所以要有http编解码器
pipeline.addLast(new HttpServerCodec());
// 对写大数据流的支持
pipeline.addLast(new ChunkedWriteHandler());
// 对HttpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
// 几乎在netty中的编程都会使用到此handler
pipeline.addLast(new HttpObjectAggregator(1024*64));
//===============以上用于支持http协议===========================
/**
* websocket服务器处理的协议,用于指定给客户端连接访问的路由: /ws
* 此handler会处理一些繁重复杂的事情
* 握手: handshaking(close,ping,pong)
* 对于websocket,都是以frames进行传输的,不同的数据类型对应的frames也不同
*/
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
// 自定义handler
pipeline.addLast(new ChatHandler());
}
}
/**
*
* @author Edward
* 处理消息的handler
* TextWebSocketFrame:在netty中,是用于为websocket专门处理文本的对象,frame是消息的载体
*/
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{
// 用于记录和管理所有客户端的channel
private static ChannelGroup clients =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg)
throws Exception {
// 获取客户端传输过来的消息
String content = msg.text();
System.out.println("接收到的数据:" + content);
for(Channel channel : clients) {
channel.writeAndFlush(
new TextWebSocketFrame("[服务器在]" + LocalDateTime.now() + "接收到的消息为:" + content));
}
// 与上面的for循环功能一致
// clients.writeAndFlush(
// new TextWebSocketFrame("[服务器在]" + LocalDateTime.now() + "接收到的消息为:" + content));
}
/**
* 当客户端连接服务端之后(打开连接)
* 获取客户端的channel,并且放到ChannelGroup中进行管理
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
clients.add(ctx.channel());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
// 当触发handlerRemoved,ChannelGroup会自动移除对应客户端的channel
// clients.remove(ctx.channel());
System.out.println("客户端断开,channel对应的长ID为:" + ctx.channel().id().asLongText());
System.out.println("客户端断开,channel对应的短ID为:" + ctx.channel().id().asShortText());
}
}