添加依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.25.Final</version>
</dependency>
ws服务端
package com.imooc.netty.websocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @author 朝花不迟暮
* @version 1.0
* @date 2020/12/28 22:21
*/
public class WSServer
{
public static void main(String[] args)
{
//主子线程组
NioEventLoopGroup mainGroup = new NioEventLoopGroup();
NioEventLoopGroup subGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = null;
try
{
serverBootstrap = new ServerBootstrap();
serverBootstrap.group(mainGroup, subGroup)//设置主从线程组
.channel(NioServerSocketChannel.class)//设置nio双向通道
.childHandler(new WSServerInitializer());//子处理器,用于处理workerGroup
ChannelFuture future = serverBootstrap.bind(8088).sync();
//监听关闭的channel,设置为同步方式
future.channel().closeFuture().sync();
} catch (Exception e)
{
e.printStackTrace();
} finally
{
//优雅关闭
mainGroup.shutdownGracefully();
subGroup.shutdownGracefully();
}
}
}
子处理器
package com.imooc.netty.websocket;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
/**
* @author 朝花不迟暮
* @version 1.0
* @date 2020/12/28 22:37
*/
public class WSServerInitializer extends ChannelInitializer<SocketChannel>
{
@Override
protected void initChannel(SocketChannel ch) throws Exception
{
ChannelPipeline pipeline = ch.pipeline();
//ws基于http协议,所以要有编解码器
pipeline.addLast(new HttpServerCodec());
//对写入大数据流的支持
pipeline.addLast(new ChunkedWriteHandler());
//在netty中,几乎都会使用到这个handler
pipeline.addLast(new HttpObjectAggregator(1024 * 64));
//服务器处理的协议,用户给客户端连接访问的路由
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
// 自定义的handler
pipeline.addLast(new ChatHandler());
}
}
该类继承ChannelInitializer
,泛型为SocketChannel
!通过获取的管道,使用addLast
添加ws的基本配置。上面的代码就是基本配置!
自定义消息处理
package com.imooc.netty.websocket;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.time.LocalDateTime;
/**
* @author 朝花不迟暮
* @version 1.0
* @date 2020/12/28 22:52
*/
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 msgText = msg.text();
System.out.println("接收到的数据: " + msgText);
// for (Channel client : clients)
// {
// client.writeAndFlush(new TextWebSocketFrame("[服务器接收到的消息]"
// + LocalDateTime.now() + " 接收到的消息为: " + msgText));
// }
clients.writeAndFlush(new TextWebSocketFrame("[服务器接收到的消息]"
+ LocalDateTime.now() + " 接收到的消息为: " + msgText));
}
/**
* @Description: 当客户端连接服务端之后, 获取到客户端的channel, 并且放到channelGroup中
* @Param: ctx
* @return:
* @Author: 朝花不迟暮
* @Date: 2020/12/28
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception
{
Channel channel = ctx.channel();
clients.add(channel);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception
{
System.out.println("长id: " + ctx.channel().id().asLongText());
System.out.println("短id: " + ctx.channel().id().asShortText());
}
}
前端页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
</head>
<body>
<div>发送消息:</div>
<input type="text" id="msgContent"/>
<input type="button" value="点我发送" onclick="CHAT.chat()"/>
<div>接受消息:</div>
<div id="receiveMsg" style="background-color: gainsboro;"></div>
<script type="application/javascript">
window.CHAT = {
socket: null,
init: function () {
if (window.WebSocket) {
CHAT.socket = new WebSocket("ws://192.168.0.102:8088/ws");
CHAT.socket.onopen = function () {
console.log("连接建立成功...");
},
CHAT.socket.onclose = function () {
console.log("连接关闭...");
},
CHAT.socket.onerror = function () {
console.log("发生错误...");
},
CHAT.socket.onmessage = function (e) {
console.log("接受到消息:" + e.data);
var receiveMsg = document.getElementById("receiveMsg");
var html = receiveMsg.innerHTML;
receiveMsg.innerHTML = html + "<br/>" + e.data;
}
} else {
alert("浏览器不支持websocket协议...");
}
},
chat: function () {
var msg = document.getElementById("msgContent");
CHAT.socket.send(msg.value);
}
};
CHAT.init();
</script>
</body>
</html>
测试效果