WSServer
package com.mqtt.netty2;
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;
public class WSServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup mainGroup = new NioEventLoopGroup();
EventLoopGroup subGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(mainGroup, subGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new WSServerInitializer());
ChannelFuture future = serverBootstrap.bind(8088).sync();
future.channel().closeFuture().sync();
} finally {
mainGroup.shutdownGracefully();
subGroup.shutdownGracefully();
}
}
}
WSServerInitializer
package com.mqtt.netty2;
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 WSServerInitializer 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());
// 设置聚合器
pipeline.addLast(new HttpObjectAggregator(1024 * 64));
//====================== 以上是用于支持http协议 =====================
// websocket 服务器处理的协议,用于指定给客户端连接访问的路由
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
pipeline.addLast(new ChatHandler());
}
}
ChatHandler
package com.mqtt.netty2;
import java.time.LocalDateTime;
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;
/**
* 处理消息的handler
* TextWebSocketFrame 在netty中,用於為websocket專門用於處理文本的對象
* */
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("接收到的数据:" + content);
// 第一種方法
// for(Channel channel: clients) {
// channel.writeAndFlush(
// new TextWebSocketFrame("[服务器接收到消息:]" +
// LocalDateTime.now() + "接收到消息:" + content ));
// }
// 第二種方法
clients.writeAndFlush(new TextWebSocketFrame("[服务器接收到消息:]" +
LocalDateTime.now() + "接收到消息:" + content ));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// 當客戶端連接服務器端之後,獲取客戶端的channel,並且放到channelGroup中去進行管理
clients.add(ctx.channel() );
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
// 當触发handleReomved,ChannelGroup会自动移除对应客户端的channel
clients.remove(ctx.channel());
System.out.println("客戶端断开,channel对应的長id"+ctx.channel().id().asLongText());
System.out.println("客戶端断开,channel对应的短id" +ctx.channel().id().asShortText());
}
}
页面
在hbuilder 新建页面 index.html
<!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="recciveMsg" style="background-color: yellow;">
</div>
<script type="application/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("连接建立成功");
},
CHAT.socket.onclose = function(){
console.log("连接关闭...");
},
CHAT.socket.onerror = function(){
console.log("发生错误...");
},
CHAT.socket.onmessage = function(e){
console.log("接收到消息:" + e.datta );
var recciveMsg = document.getElementById("recciveMsg");
var html = recciveMsg.innerHTML;
recciveMsg.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>
心跳
关于作者
王硕,网名信平,十多年软件开发经验,业余架构师,精通Java/Python/Go等,喜欢研究技术,著有《PyQt 5 快速开发与实战》《Python 3.* 全栈开发》,多个业余开源项目托管在GitHub上,欢迎微博交流。