Netty构建WebSocket服务器(服务器端)
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()); } }