当我们搭建起来服务器之后,我们就开始尝试着去构建一个简单的聊天室的功能
WsServer的实现
服务器实现与第一节的实现基本相一致
public static void main(String[] args) {
//主线程组
EventLoopGroup mainGroup = new NioEventLoopGroup();
//子线程组
EventLoopGroup sonGroup = new NioEventLoopGroup();
//服务器启动组件
ServerBootstrap server = new ServerBootstrap();
//把两个线程组加入到启动组件中
server.group(mainGroup, sonGroup)
//设置channel为NioServerSocketChannel
.channel(NioServerSocketChannel.class)
//自定义channelHandler
.childHandler(new WsServerIntializer());
try {
ChannelFuture channelFuture =
//绑定端口为8088
server.bind(8088)
//同步
.sync();
//关闭
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//优雅关闭主线程组,子线程组
mainGroup.shutdownGracefully();
sonGroup.shutdownGracefully();
}
}
WsServerInititalizer的实现
public class WsServerIntializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline channelPipeline = ch.pipeline();
//============================Http 协议的支持=================================
channelPipeline.addLast("HttpServerCodec", new HttpServerCodec());
//支持写入大数据流
channelPipeline.addLast("ChunkedWriteHandler", new ChunkedWriteHandler());
//对Http进行聚合,聚合为FullHttpRequest或FullHttpResponse
//几乎所有对netty的编程都会用到此handler
channelPipeline.addLast("HttpObjectAggregator", new HttpObjectAggregator(1024 * 64));
//============================WebSocket 协议的支持=================================
//ws服务器处理的协议并且用于客户端访问服务器的路由
channelPipeline.addLast("WebSocketServerProtocolHandler", new WebSocketServerProtocolHandler("/ws"));
channelPipeline.addLast(new ChatHandler());
}
}
ChatHandler(自定义Handler)的实现
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
//ChannelGroup 多个channel的集中聚合
public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
//接收到的msg
String content = msg.text();
System.out.println("接收到的消息:" + content);
for (Channel channel : clients) {
channel.writeAndFlush(
//注意,writeAndFlush只能用Object类型的参数,不能传String类型,所以我们现在传的是TextWebSocketFrame
new TextWebSocketFrame("[服务器接收消息]" + LocalDate.now() + ",消息为:" + content));
}
}
/**
* 当浏览器关闭之后,客户端将该channel移除出组
*
* @param ctx
* @throws Exception
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
clients.remove(ctx.channel());
System.out.println("客户端断开,长id:" + ctx.channel().id().asLongText());
System.out.println("客户端断开,短id:" + ctx.channel().id().asLongText());
}
/**
* 当浏览器连接之后,客户端获取这个channel加入组中进行管理
*
* @param ctx
* @throws Exception
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
clients.add(ctx.channel());
}
}
我们编写相应的Html5文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<div>发送消息:</div>
<input type="text" id="msgContent" />
<button type="button" onclick="CHAT.chat()">发送</button>
<div>接收消息</div>
<div id="receiveMsg" style="background-color: gainsboro;"></div>
</body>
<script type="application/javascript">
//定义一个CHAT对象
window.CHAT={
//socket为null
socket:null,
//初始化方法
init:function(){
//判断浏览器是否支持webSocket,因为有些浏览器不支持。
if(window.WebSocket){
//Socket一个方法
CHAT.socket=new WebSocket("ws://127.0.0.1:8088/ws")
//开启socket状态
CHAT.socket.onopen=function(){
document.getElementById("receiveMsg").innerHTML="建立连接成功"
},
//关闭socket状态
CHAT.socket.onclose=function(){
document.getElementById("receiveMsg").innerHTML="连接建立关闭"
},
//发生错误状态
CHAT.socket.onerror=function(){
document.getElementById("receiveMsg").innerHTML="发生错误"
},
//接受消息
CHAT.socket.onmessage=function(e){
console.log("接受到消息:"+e.data)
//接受消息div里面的内容
var receiveMsg=document.getElementById("receiveMsg");
var html=receiveMsg.innerHTML;
//websocket返回的内容与receiver的内容进行合并
receiveMsg.innerHTML=html+"</br>"+e.data
}
}else{
alert("不支持websocketx协议")
}
},
//发送
chat:function(){
var msg=document.getElementById("msgContent")
CHAT.socket.send(msg.value)
}
}
//初始化
CHAT.init()
</script>
</html>
可以看到连接成功
当我们发送success,另个页面也有推送。
断开连接也有响应