您的位置:首页 > 其它

Netty5 + WebSocket 练习

2016-03-07 08:44 288 查看
1. 了解WebSocket知识
  略
2. websocket实现系统简单反馈时间

  WebSocketServerHandler.java

package com.jieli.nettytest.websocketserver;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
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.stream.ChunkedWriteHandler;

public class WebSocketServer {

public void run(int port){
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//HttpServerCodec将请求和应答消息编码或解码为HTTP消息
//通常接收到的http是一个片段,如果想要完整接受一次请求所有数据,我们需要绑定HttpObjectAggregator
//然后就可以收到一个FullHttpRequest完整的请求信息了
//ChunkedWriteHandler 向客户端发送HTML5文件,主要用于支持浏览器和服务器进行WebSocket通信
//WebSocketServerHandler自定义Handler
ch.pipeline().addLast("http-codec", new HttpServerCodec())
.addLast("aggregator", new HttpObjectAggregator(65536)) //定义缓冲大小
.addLast("http-chunked", new ChunkedWriteHandler())
.addLast("handler", new WebSocketServerHandler());
}
});

ChannelFuture f = b.bind(port).sync();
System.out.println("start...");
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}

public static void main(String[] args) {
new WebSocketServer().run(7777);
}
}


  WebSocketServerHandler.java

package com.jieli.nettytest.websocketserver;

import java.util.logging.Level;
import java.util.logging.Logger;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderUtil;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;

public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>{

/**
* 日志
*/
private static final Logger logger =
Logger.getLogger(WebSocketServerHandler.class.getName());
/**
* 全局websocket
*/
private WebSocketServerHandshaker handshaker;

@Override
protected void messageReceived(ChannelHandlerContext ctx, Object msg)
throws Exception {
//普通HTTP接入
if(msg instanceof FullHttpRequest){
handleHttpRequest(ctx, (FullHttpRequest) msg);
}else if(msg instanceof WebSocketFrame){ //websocket帧类型 已连接
//BinaryWebSocketFrame CloseWebSocketFrame ContinuationWebSocketFrame
//PingWebSocketFrame PongWebSocketFrame TextWebScoketFrame
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}

private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request){
//如果http解码失败 则返回http异常 并且判断消息头有没有包含Upgrade字段(协议升级)
if(!request.decoderResult().isSuccess()
|| (!"websocket".equals( request.headers().get("Upgrade")))    ){
sendHttpResponse(ctx, request, new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
return ;
}
//构造握手响应返回
WebSocketServerHandshakerFactory ws = new WebSocketServerHandshakerFactory("", null, false);
handshaker = ws.newHandshaker(request);
if(handshaker == null){
//版本不支持
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
}else{
handshaker.handshake(ctx.channel(), request);
}
}
/**
* websocket帧
* @param ctx
* @param frame
*/
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){
//判断是否关闭链路指令
if(frame instanceof CloseWebSocketFrame){
handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
return ;
}
//判断是否Ping消息 -- ping/pong心跳包
if(frame instanceof PingWebSocketFrame){
ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
return ;
}
//本程序仅支持文本消息, 不支持二进制消息
if(!(frame instanceof TextWebSocketFrame)){
throw new UnsupportedOperationException(
String.format("%s frame types not supported", frame.getClass().getName()));
}

//返回应答消息 text文本帧
String request = ((TextWebSocketFrame) frame).text();
//打印日志
if(logger.isLoggable(Level.FINE)){
logger.fine(String.format("%s received %s", ctx.channel(), request));
}
//发送到客户端websocket
ctx.channel().write(new TextWebSocketFrame(request
+ ", 欢迎使用Netty WebSocket服务, 现在时刻:"
+ new java.util.Date().toString()));
}

/**
* response
* @param ctx
* @param request
* @param response
*/
private static void sendHttpResponse(ChannelHandlerContext ctx,
FullHttpRequest request, FullHttpResponse response){
//返回给客户端
if(response.status().code() != HttpResponseStatus.OK.code()){
ByteBuf buf = Unpooled.copiedBuffer(response.status().toString(), CharsetUtil.UTF_8);
response.content().writeBytes(buf);
buf.release();
HttpHeaderUtil.setContentLength(response, response.content().readableBytes());
}
//如果不是keepalive那么就关闭连接
ChannelFuture f = ctx.channel().writeAndFlush(response);
if(!HttpHeaderUtil.isKeepAlive(response)
|| response.status().code() != HttpResponseStatus.OK.code()){
f.addListener(ChannelFutureListener.CLOSE);
}
}

/**
* 异常 出错
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}


  WebSocketServer.html (这个随便放都可以,到时候双击打开这个即可,不由服务器提供)

<html>
<head>
<meta charset="utf-8">
<title>Netty websocket 时间服务器</title>
</head>
<body>
<form action="" onsubmit="return false;">
<input type="text" name="message" value="..."/>
<br>
<input type="button" value="send" value="发送websocket请求消息" onclick="send(this.form.message.value);" />
<hr color="blue">
<h3>服务器返回信息</h3>
<textarea id="responseText" rows="10" cols=""></textarea>
</form>
</body>

<script type="text/javascript">
var socket;
if(!window.WebSocket){
window.WebSocket = window.MozWebSocket;
}
if(window.WebSocket){
socket = new WebSocket("ws://localhost:7777/websocket");
socket.onmessage = function(event){
var ta = document.getElementById('responseText');
ta.value="";
ta.value=event.data;
};
socket.onopen = function(event){
var ta = document.getElementById('responseText');
ta.value = "打开websocket服务正常";
}
socket.onclose = function(event){
var ta = document.getElementById('responseText');
ta.value="";
ta.value="websocket关闭";
}
}else{
alert("对不起,您的浏览器不支持WebSocket.");
}

function send(message){
if(!window.WebSocket){
return ;
}
if(socket.readyState == WebSocket.OPEN){
socket.send(message);
}else{
alert("WebSocket 连接创建失败.");
}
}
</script>
</html>


  运行结果

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body>
<script type="text/javascript">
var socket;
if (!window.WebSocket) {
window.WebSocket = window.MozWebSocket;
}
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:8080/ws");
socket.onmessage = function(event) {
var ta = document.getElementById('responseText');
ta.value = ta.value + '\n' + event.data
};
socket.onopen = function(event) {
var ta = document.getElementById('responseText');
ta.value = "连接开启!";
};
socket.onclose = function(event) {
var ta = document.getElementById('responseText');
ta.value = ta.value + "连接被关闭";
};
} else {
alert("你的浏览器不支持 WebSocket!");
}

function send(message) {
if (!window.WebSocket) {
return;
}
if (socket.readyState == WebSocket.OPEN) {
socket.send(message);
} else {
alert("连接没有开启.");
}
}
</script>
<form onsubmit="return false;">
<h3>WebSocket 聊天室:</h3>
<textarea id="responseText" style="width: 500px; height: 300px;"></textarea>
<br>
<input type="text" name="message"  style="width: 300px" value="Welcome to localhost">
<input type="button" value="发送消息" onclick="send(this.form.message.value)">
<input type="button" onclick="javascript:document.getElementById('responseText').value=''" value="清空聊天记录">
</form>
<br>
Netty SEO 优化
Netty 是什么
Netty 怎么样
Netty4 Netty5 区别
Netty 效率
Netty 版本区别
Netty 和 Mina
Netty 网络编程
Netty Java 网络编程
Netty Java Socket NIO
NIO 编程
Netty NIO 开发
Netty3 Netty4 Netty5
Netty 好处
Netty 一般注意什么
Netty 例子程序
Netty Hello World
Netty 聊天程序
Netty Web HTML HTTP FTP SSL
Netty UDP TCP WebSocket 练习
Netty 连接数
Netty 源码
<br>
</body>
</html>


View Code
  运行结果,依次运行1,2,3



  服务器打印结果



参考资料:
  《Netty 权威指南》
  https://zh.wikipedia.org/wiki/WebSocket
  https://www.zhihu.com/question/20215561
  http://waylau.com/netty-websocket-chat/

本文地址:/article/6193172.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: