netty 对websocket 支持
2017-08-26 本文已影响285人
持续进步者
WebSocket
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信————允许服务器主动发送信息给客户端。
WebSocket解决了那些问题
-
1,http 是无状态,基于请求/响应模型,导致了不识别用户,每次请求都是一个新的用户,
这就产生了cookie,session 记录用户的状态的技术。 -
2,http1.1 进行网络请求可以重用既有的连接, WebSocket只需进行连接一次。
-
3,向客户端推送数据 http轮询:http的轮询实现是客户端每个一段时间就进行网络请求,
如果服务器端没有数据返回也就表示这次请求是无效的,多次这样的网络请求会影响网络带宽,WebSocket是基于tcp全双工通信,只要连接通道建立,服务器可以向客户端推送数据。 -
4,http 请求包括header 和 要返回的结果返回给客户端,往往header大于内容的容量,
websoket 浏览器和服务器端会建立长连接,双方式对等的,只要发送数据本省,不在需要任何header的信息 。
netty 服务器端
- 1,MyServer.java
public class MyServer {
public static void main(String ...arg) throws Exception{
// 负责接收客户端连接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
// 负责处理连接
NioEventLoopGroup wokerGroup = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,wokerGroup)
.handler(new LoggingHandler(LogLevel.INFO))
.channel(NioServerSocketChannel.class)
.childHandler(new WebSocketChannelInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(9999).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
wokerGroup.shutdownGracefully();
}
}
}
- 2,WebSocketChannelInitializer.java
public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(8192));
//websocket 请求路径
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
pipeline.addLast(new TextWebSocketFrameHandler());
}
}
- 3,TextWebSocketFrameHandler.java
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
System.out.println("服务器收到:"+msg.text());
ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器时间:"+ LocalDateTime.now()));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//每个channel 都有一个唯一的id
System.out.println("handlerAdded: "+ctx.channel().id().asLongText());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerRemoved: "+ctx.channel().id().asLongText());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
WebSocket js 使用
- 1,创建对象
var ws = new WebSocket(url,name);
- 2,发送文本消息
ws.send(msg);
- 3,接收消息
ws.onmessage = (function(){...})();
- 4,错误处理
ws.onerror = (function(){...})();
- 5,关闭连接
ws.close();
客户端端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>websoket 客户端</title>
</head>
<body>
<form onsubmit="return false">
<textarea name="message" style="width:400px;height: 200px"></textarea>
<input type="button" value="发送数据" onclick="send(this.form.message.value)">
<h3>服务器输出:</h3>
<textarea id="responseText" style="width: 400px; height: 300px"></textarea>
<input type="button" onclick="javascript:document.getElementById('responseText').value=''" value="清空内容">
</form>
</body>
<script type="text/javascript">
var socket;
if (window.WebSocket) {
socket = new WebSocket("ws://127.0.0.1:9999/ws")
var ta = document.getElementById("responseText");
socket.onmessage = function (event) {
ta.value = ta.value + "\n" + event.data;
}
socket.onopen = function (event) {
ta.value = "连接开启"
}
socket.onclose = function (event) {
ta.value = ta.value + "\n" + "连接关闭";
}
} else {
alert("浏览器不支持websocket")
}
function send(message) {
if(!window.WebSocket) {
return;
}
if(socket.readyState == WebSocket.OPEN){
socket.send(message)
}else{
alert("连接尚未成功")
}
}
</script>
</html>