/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.yxw.task; import java.net.SocketAddress; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.GlobalEventExecutor; public class CustomTextFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { //DefaultChannelGroup recipients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); private ChannelGroup recipients; public CustomTextFrameHandler(ChannelGroup recipients) { this.recipients= recipients; } @Override protected void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception { String request = frame.text(); //ctx.channel().writeAndFlush(new TextWebSocketFrame(request.toUpperCase())); System.out.println("size:"+recipients.size()); recipients.write(new TextWebSocketFrame(request.toUpperCase())); } @Override public void channelActive(ChannelHandlerContext ctx){ recipients.add(ctx.channel()); System.out.println("connect:"+recipients.size()); } @Override public void handlerRemoved(ChannelHandlerContext ctx){ try { recipients.remove(ctx.channel()); System.out.println("删除channel成功"+recipients.size()); } catch (Exception ex) { System.out.println("删除channel失败"+ex.getMessage()); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } }
以上是 CustomTextFrameHandler.java 内容,
/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.yxw.task; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.GlobalEventExecutor; /** * A WebSocket Server that respondes to requests at: * * <pre> * http://localhost:8080/websocket * </pre> * * The example differs from many of the other examples in Netty in that is does * not have an acomponying client. Instead a html page is provided that * interacts with this server. <br> * Open up the following file a web browser that supports WebSocket's: * * <pre> * example/src/main/resources/websocketx/html5/websocket.html * </pre> * * The html page is very simple were you simply enter some text and the server * will echo the same text back, but in uppercase. You, also see getStatus messages * in the "Response From Server" area when client has connected, disconnected * etc. * */ public class WebSocketServer { private final int port; public WebSocketServer(int port) { this.port = port; } public void run() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { final ServerBootstrap sb = new ServerBootstrap(); sb.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(final SocketChannel ch) throws Exception { ch.pipeline().addLast( new HttpResponseEncoder(), new HttpRequestDecoder(), new HttpObjectAggregator(65536), new WebSocketServerProtocolHandler("/websocket"), new CustomTextFrameHandler(new DefaultChannelGroup(GlobalEventExecutor.INSTANCE))); } }).option(ChannelOption.SO_BACKLOG, 65536) .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.TCP_NODELAY, true); //.childOption(ChannelOption.SO_BROADCAST, true); //bootstrap.setOption("child.reuseAddress", true); //bootstrap.setOption("child.tcpNoDelay", true); //bootstrap.setOption("child.keepAlive", true); final Channel ch = sb.bind(port).sync().channel(); System.out.println("Web socket server started at port " + port); ch.closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new WebSocketServer(port).run(); } }
以上是WebSocketServer.java 的内容, 基本是Netty5 自带的例子改了一点点,
运行之后,命令行输出:
Web socket server started at port 8080
connect:1
size:1
connect:1
size:1
recipients.size() 始终是1, 于是这个程序不能实现广播, 不知道问题出自哪里?
这里忍不住吐槽一下:
1. Netty 不同版本,其接口,方法改变很大,新版本不兼容旧的,一些网上搜到的代码基本都不能用;
2. Netty 上的github上的代码是最新的, 所以想运行example必须用最新版本;
3. 网上的资料太少了;
4. 官方的User guide 和example实在too simple了, 弄了半天还是几个hellow world, 麻烦有点深度写点有用的东西行不, 毕竟项目是用来解决实际问题了, 不是用来写hellow world;