注意:先启动SpringBoot项目,再启动WebSocketServer!!!
代码:
1.pom.xml代码:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
<groupId>com.yjq.programmergroupId>
<artifactId>ChatDemoartifactId>
<version>1.0-SNAPSHOTversion>
<name>ChatDemoname>
<url>http://www.example.comurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>io.nettygroupId>
<artifactId>netty-allartifactId>
<version>4.1.42.Finalversion>
dependency>
dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
pluginManagement>
build>
project>
2.WebSocketServer代码:
package com.yjq.programmer.websocket;
import com.yjq.programmer.netty.HelloServerInitializer;
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;
/**
* @author 杨杨吖
* @QQ 823208782
* @WX yjqi12345678
* @create 2022-10-03 8:28
*/
public class WebSocketServer {
public static void main(String[] args) throws Exception {
// 定义一对线程组 主线程组 用于接收客户端的连接请求,不做任何处理
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 定义一对线程组 从线程组 主线程组会把任务丢给从线程组,让从线程组去处理
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// netty服务器的创建,ServerBootstrap是一个启动类
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup) // 设置主从线程组
.channel(NioServerSocketChannel.class) // 设置NIO双向通道类型
.childHandler(new WebSocketServerInitializer()); // 子处理器,用于处理workerGroup
// 启动server,绑定8088端口启动,并且同步等待方式启动
ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();
// 监听关闭的channel, 设置为同步的方式
channelFuture.channel().closeFuture().sync();
} finally {
// 关闭我们的主线程组和从线程组
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
3.WebSocketServerInitializer代码:
package com.yjq.programmer.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;
/**
* @author 杨杨吖
* @QQ 823208782
* @WX yjqi12345678
* @create 2022-10-03 8:34
*/
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
// 通过SocketChannel去获取对应的管道pipeline
ChannelPipeline pipeline = channel.pipeline();
// 通过管道,添加handler HttpServerCodec是netty自己提供的助手类
// 当请求到服务端时候,我们需要做解码,响应到客户端时候需要做编码
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
// 对写大数据流的支持
pipeline.addLast("ChunkedWriteHandler", new ChunkedWriteHandler());
// 对HttpMessage进行聚合 聚合成FullHttpRequest或FullHttpResponse
// 几乎在netty的编程中,都会用到这个handler
pipeline.addLast("HttpObjectAggregator", new HttpObjectAggregator(1024*64));
// 以上用于支持http协议
// websocket服务器处理的协议 并且用于指定给客户端连接访问的路由:/ws
pipeline.addLast("WebSocketServerProtocolHandler", new WebSocketServerProtocolHandler("/ws"));
// 自定义的handler
pipeline.addLast(new ChatHandler());
}
}
4.ChatHandler代码:
package com.yjq.programmer.websocket;
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;
/**
* @author 杨杨吖
* @QQ 823208782
* @WX yjqi12345678
* @create 2022-10-03 8:50
*/
/**
* 处理消息的handler
* TextWebSocketFrame:在netty中,是用于为websocket专门处理文本的对象,frame是消息的载体
*/
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
// 用于记录和管理所有客户端的ChannelGroup
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) {
// 不能直接writeAndFlush收到的content字符串信息,必须封装到frame载体中输出
channel.writeAndFlush(new TextWebSocketFrame("系统消息:" + content));
}
// clients.writeAndFlush(new TextWebSocketFrame("系统消息:" + content));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// 当客户端连接服务端之后,获取客户端的channel,并且放到ChannelGroup中去进行管理
clients.add(ctx.channel());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
// 这步是多余的,当断开连接时候ChannelGroup会自动移除对应的channel
clients.remove(ctx.channel());
System.out.println(ctx.channel().id().asLongText());
}
}
5.index.html代码:
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Netty-Websockettitle>
<script type="text/javascript">
let socket;
if(window.WebSocket){
socket = new WebSocket("ws://localhost:8088/ws");
socket.onmessage = function(event){
let textarea = document.getElementById('responseText');
textarea.value += event.data+"\r\n";
};
socket.onopen = function(event){
let textarea = document.getElementById('responseText');
textarea.value = "Netty-WebSocket服务器。。。。。。连接 \r\n";
};
socket.onclose = function(event){
let textarea = document.getElementById('responseText');
textarea.value = "Netty-WebSocket服务器。。。。。。关闭 \r\n";
};
} else {
alert("您的浏览器不支持WebSocket协议!");
}
function send(){
if(!window.WebSocket){return;}
if(socket.readyState === WebSocket.OPEN) {
let message = document.getElementById('message').value;
socket.send(message);
} else {
alert("WebSocket 连接没有建立成功!");
}
}
script>
head>
<body>
<form onSubmit="return false;">
<label>文本label><input type="text" id="message" name="message" placeholder="这里输入消息" /> <br />
<br /> <input type="button" value="发送ws消息"
onClick="send()" />
<hr color="black" />
<h3>服务端返回的应答消息h3>
<textarea id="responseText" style="width: 1024px;height: 300px;">textarea>
form>
body>
html>