springboot+netty+websocket收发消息
1.创建spring boot的工程,在这里就不赘述怎么创建了
2.引入netty的依赖
<dependency> <groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
3.编写websocket服务
import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.stereotype.Component;
@Component
public class WSServer {
private static class SingletonWSServer {
static final WSServer instance = new WSServer();
}
public static WSServer getInstance() {
return SingletonWSServer.instance;
}
private EventLoopGroup mainGroup;
private EventLoopGroup subGroup;
private ServerBootstrap server;
private ChannelFuture future;
public WSServer() {
mainGroup = new NioEventLoopGroup();
subGroup = new NioEventLoopGroup();
server = new ServerBootstrap();
server.group(mainGroup, subGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WSServerInitialize());
}
public void start() {
this.future = server.bind(8088);
System.err.println("netty websocket start finish.");
}
}
4.初始化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.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
public class WSServerInitialize 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));
/**
* websocket 服务器处理协议,用于指定给客户端访问的路由: /ws
* 本handler会帮你处理一些繁重而复杂的事情
* 会帮你处理握手动作:handshaking(ping、pong、close)ping + pong = 心跳
* 对于websocket来讲,都是通过frames进行传输的,不同的数据类型对应的frames也不同
*/
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
// 自定义的handler
pipeline.addLast(new ChatHandler());
}
}
5.编写接收信息处理handler
import io.netty.channel.Channel;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.GlobalEventExecutor;
import java.time.LocalDateTime;
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
// 用于记录和管理所有的客户端的channel
private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame msg) throws Exception {
// 获取客户端传输过来的消息
String content = msg.text();
System.out.println("接收到数据:" + content);
for (Channel channel : clients) {
channel.writeAndFlush(new TextWebSocketFrame("服务端在[" + LocalDateTime.now() + "]
接收到消息,消息为:" + content));
}
}
/**
* 当客户端连接服务端之后(打开链接)
* 获取客户端的channel,并且放到channelGroup中去管理
* @param ctx
* @throws Exception
*/
@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());
}
}
6.监听spring boot工程的启动
import org.springframework.context.ApplicationListener;import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Component
public class NettyBooter implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext().getParent() == null) {
try {
WSServer.getInstance().start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
7.启动项目,在页面上测试
<!DOCTYPE html><html>
<head>
<meta charset="utf-8">
<title>hello</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: yellow;"></div>
<script type="text/javascript">
window.CHAT = {
socket: null,
init: function() {
if (window.WebSocket) {
CHAT.socket = new WebSocket("ws://127.0.0.1:8088/ws");
CHAT.socket.onopen = function() {
console.log("connect success...");
},
CHAT.socket.onclose = function() {
console.log("connect close...");
},
CHAT.socket.onerror = function() {
console.log("connect error...");
},
CHAT.socket.onmessage = function(e) {
console.log("receive msg: " + e.data);
var receiveMsg = document.getElementById("receiveMsg");
var html = receiveMsg.innerHTML;
receiveMsg.innerHTML = html + "<br />" + e.data;
}
} else {
alert("do not support websocket..");
}
},
chat: function() {
var msgContent = document.getElementById("msgContent");
CHAT.socket.send(msgContent.value);
}
}
CHAT.init();
</script>
</body>
</html>
以上是 springboot+netty+websocket收发消息 的全部内容, 来源链接: utcz.com/z/514821.html