这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
之前我们实战过Netty实现Http的小案例,今天我们开始Websocket的实现,实战之前先来了解下Websocetk的入门!
什么是Websocket?
WebSocket 通过“Upgrade handshake(升级握手)”从标准的 HTTP 或HTTPS 协议转为 WebSocket。因此,使用 WebSocket 的应用程序将始终以 HTTP/S 开始,然后进行升级。在什么时候发生这种情况取决于具体的应用;它可以是在启动时,或当一个特定的 URL 被请求时。
在我们的应用中,当 URL 请求以“/ws”结束时,我们才升级协议为WebSocket。否则,服务器将使用基本的 HTTP/S。一旦升级连接将使用的WebSocket 传输所有数据。
Websocket的处理过程?
- 客户端连接到服务器
- HTTP请求页面或Websocket"Upgrade handshake"
- 服务端处理发起连接的客户端
- 响应客户端对应URL的请求,当访问的URL有"/ws",处理Websocket"Upgrade handshake"
- 升级握手完成后 ,通过 WebSocket 发送聊天消息
实战:
四个页面:
第一步,创建WWSServer页面
/**
* @version 1.0
* @date 2021/8/31 19:44
*/
public class WWSServer {
int port = 8081;
public void start() {
// 定义一对线程组
// 主线程组, 用于接受客户端的连接,
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 从线程组, 负责IO交互工作
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//netty服务器的创建, 辅助工具类,用于服务器通道的一系列配置
ServerBootstrap server = new ServerBootstrap();
//绑定两个线程组
server.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WSServerInitialzer());
// 启动server,并且设置8088为启动的端口号,同时启动方式为同步
ChannelFuture future = server.bind(port).sync();
System.out.println(" server start up on port : " + port);
//等待服务端口关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
复制代码
第二步:创建WSServerInitializer页面
/**
* @version 1.0
* @date 2021/8/31 19:46
*/
public class WSServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//处理http消息的编解码
pipeline.addLast("httpServerCodec", new HttpServerCodec());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
// 添加对httpWebsocket的支持
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
// 自定义的handler
pipeline.addLast(new ChatHandler());
}
}
复制代码
第三步,创建ChatHandler页面
/**
* @Description: 处理消息的handler
* @version 1.0
* @date 2021/8/31 19:56
*/
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("接受到id为 "+ ctx.channel().id() +" 的数据:" + content);
// 向客户端发送数据
clients.writeAndFlush(new TextWebSocketFrame("我是Websocket Server服务器,我收到你的消息为:" + 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,所以下面的remove不用我们再手写
System.out.println("客户端断开,channel对应的长id为:" + ctx.channel().id().asLongText());
System.out.println("客户端断开,channel对应的短id为:" + ctx.channel().id().asShortText());
}
}
复制代码
第四部调用start方法
测试:
直接找个在线测试websocket进行测试,并成功反馈结果