一起学netty(17)netty实现websocket协议
Websocket协议和http协议的关系
websocket是基于TCP的一个应用协议,与HTTP协议的关联之处在于websocket的握手数据被HTTP服务器当作HTTP包来处理,主要通过Update request HTTP包建立起连接,之后的通信全部使用websocket自己的协议,就和http没啥关系了。有兴趣的同学可以多了解一下websocket协议报文的详细信息。
Netty实现websocket协议
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
public class NettyServerWebsocker {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup boot = new NioEventLoopGroup(1);
NioEventLoopGroup work = new NioEventLoopGroup(8);
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boot,work)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 建立连接时需要http协议的支持
pipeline.addLast(new HttpServerCodec());
// 以块的方式来写的处理器
pipeline.addLast(new ChunkedWriteHandler());
//netty是基于分段请求的,HttpObjectAggregator的作用是将请求分段再聚合,参数是聚合字节的最大长度
pipeline.addLast(new HttpObjectAggregator(1024*64));
//这个是websocket的handler,是netty提供的,也可以自定义,建议就用默认的
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
// 消息处理器
pipeline.addLast(new SimpleChannelInboundHandler<TextWebSocketFrame>() {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame text) throws Exception {
System.out.println(text.text());
channelHandlerContext.writeAndFlush(new TextWebSocketFrame("我收到你的消息了"+text.text()));
channelHandlerContext.fireChannelActive();
}
});
}
});
// 绑定端口
ChannelFuture bind = bootstrap.bind(8678).sync();
bind.channel().closeFuture().sync();
}
}
websocket数据包的类型有四种,TextWebSocketFrame(文本消息)、BinaryWebSocketFrame(二进制消息)、PongWebSocketFrame(PING存活检测消息)、CloseWebSocketFrame(关闭指令消息)。
上述代码只能接收TextWebSocketFrame文本类型的消息,如果需要接收其他类型的消息可以继承ChannelInboundHandlerAdapter类在channelRead方法中判断。
客户端(js代码)
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>websocket</title>
</head>
<body>
<!-- 网页控件元素,类似按钮/图片/文章什么的都写在这里 -->
<input type = "text" id ="v">
<input type = "button" id = "b" onclick="send()" value="send">
<div id ="text">
</div>
</body>
<script>
let ws = new WebSocket("ws://localhost:8678/ws");
ws.onopen = function (event) {
console.log("Send Text WS was opened.");
ws.send("hello");
};
ws.onmessage = function (event) {
console.log("response text msg: " + event.data);
document.getElementById("text").innerHTML=event.data;
};
ws.onerror = function (event) {
console.log("Send Text fired an error");
};
ws.onclose = function (event) {
console.log("WebSocket instance closed.");
};
function send(){
var v = document.getElementById("v").value;
ws.send(v);
}
</script>
</html>
fixed
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。