代码:

Server

package netty.protocol.websocket.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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; /**
* TODO
*
* @description
* @author ez
* @time 2015年6月3日 下午4:42:31
*/
public class WebSocketServer {
public void run(int port) throws Exception {
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 {
ChannelPipeline pipeline = ch.pipeline();
/*
* HttpServerCodec ,将请求和应答消息编码或者解码为HTTP消息
*/
pipeline.addLast("http-codec",
new HttpServerCodec());
/*
* HttpObjectAggregator ,
* 将HTTP消息的多个部分组合成一条完整的HTTP消息;
*/
pipeline.addLast("aggregator",
new HttpObjectAggregator(65536));
/*
* ChunkedWriteHandler ,
* 的主要作用是支持异步发送大的码流(例如大文件传输),但不占用过多的内存,防止JAVA内存溢出
*/
ch.pipeline().addLast("http-chunked",
new ChunkedWriteHandler());
/*
* WebSocketServerHandler 自己的业务处理
*/
pipeline.addLast("handler",
new WebSocketServerHandler());
}
}); Channel ch = b.bind(port).sync().channel();
System.out.println("Web socket server started at port " + port
+ '.');
System.out
.println("Open your browser and navigate to http://localhost:"
+ port + '/'); ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
int port = 8080;
if (args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
new WebSocketServer().run(port);
}
}

Handler

package netty.protocol.websocket.server;

import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
import static io.netty.handler.codec.http.HttpHeaders.setContentLength;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
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.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; import java.util.logging.Level;
import java.util.logging.Logger; /**
* TODO
*
* @description
* @author ez
* @time 2015年6月3日 下午4:42:59
*/
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger
.getLogger(WebSocketServerHandler.class.getName()); private WebSocketServerHandshaker handshaker; @Override
public void messageReceived(ChannelHandlerContext ctx, Object msg)
throws Exception {
// 传统的HTTP接入
if (msg instanceof FullHttpRequest) {
handleHttpRequest(ctx, (FullHttpRequest) msg);
}
// WebSocket接入
else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} private void handleHttpRequest(ChannelHandlerContext ctx,
FullHttpRequest req) throws Exception { // 如果HTTP解码失败,返回HHTP异常
if (!req.getDecoderResult().isSuccess()
|| (!"websocket".equals(req.headers().get("Upgrade")))) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
BAD_REQUEST));
return;
} // 构造握手响应返回,本机测试
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
"ws://localhost:8080/websocket", null, false);
handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) {
WebSocketServerHandshakerFactory
.sendUnsupportedWebSocketVersionResponse(ctx.channel());
} else {
handshaker.handshake(ctx.channel(), req);
}
} private void handleWebSocketFrame(ChannelHandlerContext ctx,
WebSocketFrame frame) { // 判断是否是关闭链路的指令
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(),
(CloseWebSocketFrame) frame.retain());
return;
}
// 判断是否是Ping消息
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()));
} // 返回应答消息
String request = ((TextWebSocketFrame) frame).text();
if (logger.isLoggable(Level.FINE)) {
logger.fine(String.format("%s received %s", ctx.channel(), request));
}
ctx.channel().writeAndFlush(
new TextWebSocketFrame(request
+ " , 欢迎使用Netty WebSocket服务,现在时刻:"
+ new java.util.Date().toString()));
for (int i = 0; i < 100; i++) {
ctx.channel().writeAndFlush(
new TextWebSocketFrame(request + i
+ new java.util.Date().toString()));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} private static void sendHttpResponse(ChannelHandlerContext ctx,
FullHttpRequest req, FullHttpResponse res) {
// 返回应答给客户端
if (res.getStatus().code() != 200) {
ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),
CharsetUtil.UTF_8);
res.content().writeBytes(buf);
buf.release();
setContentLength(res, res.content().readableBytes());
} // 如果是非Keep-Alive,关闭连接
ChannelFuture f = ctx.channel().writeAndFlush(res);
if (!isKeepAlive(req) || res.getStatus().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}

html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
Netty WebSocket 时间服务器
</head>
<br>
<body>
<br>
<script type="text/javascript">
var socket;
if (!window.WebSocket)
{
window.WebSocket = window.MozWebSocket;
}
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:8080/websocket");
socket.onmessage = function(event) {
var ta = document.getElementById('responseText'); ta.value += event.data
};
socket.onopen = function(event) {
var ta = document.getElementById('responseText');
ta.value = "打开WebSocket服务正常,浏览器支持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>
<form onsubmit="return false;">
<input type="text" name="message" value="Netty最佳实践"/>
<br><br>
<input type="button" value="发送WebSocket请求消息" onclick="send(this.form.message.value)"/>
<hr color="blue"/>
<h3>服务端返回的应答消息</h3>
<textarea id="responseText" style="width:500px;height:300px;"></textarea>
</form>
</body>
</html>

Netty WebSocket 开发的更多相关文章

  1. Netty+WebSocket 获取火币交易所数据项目

    Netty+WebSocket 获取火币交易所时时数据项目 先附上项目项目GitHub地址 spring-boot-netty-websocket-huobi 项目简介 本项目使用 SpringBoo ...

  2. Netty多协议开发

    HTTP协议开发 post与get的区别 1)get用于信息获取,post用于更新资源. 2)get数据放在请求行中,post数据放在请求体内. 3)get对数据长度有限制(2083字节),post没 ...

  3. Java和WebSocket开发网页聊天室

    小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ Java和WebSocket开发网页聊天室 一.项 ...

  4. [已解决][HTML5]基于WebSocket开发小蝌蚪应用

    前端时间在网上看到别人用WebSocket开发的小蝌蚪应用很炫酷,不过是php,于是想着用java也实现一套, 找到前端 https://github.com/danielmahal/Rumpetro ...

  5. webSocket开发chat application过程

    本次使用websocket开发chat的功能已经接近尾声,等到压力测试结束之后就可以上线了.在此记录一下整个开发过程. ---------------------------------------- ...

  6. java websocket开发的客户端程序

    最近用java websocket开发的客户端程序,在和服务端链接通后,在数据传输完毕后,客户端自动关闭了链接,如何能保持链接不断开 这个是客户端的启动类,在循环完毕后,会自动断开和服务器的链接,开始 ...

  7. Netty+WebSocket简单实现网页聊天

    基于Netty+WebSocket的网页聊天简单实现 一.pom依赖 <dependency>        <groupId>io.netty</groupId> ...

  8. netty websocket协议开发

    websocket的好处我们就不用多说了,就是用于解决长连接.服务推送等需要的一种技术. 以下我们来看一个例子: package com.ming.netty.http.websocket; impo ...

  9. 远哥谈 使用WebSocket开发在线实时看远程服务器log日志的工具

    我们开发软件的,通常会有一个测试环境/开发环境,但是系统开发完成后,还会有一个生产环境,也叫正式环境.正式环境我们一般是不能让开发人员去远程登录和维护的,一般正规的生产环境是专门的负责人员去负责更新, ...

随机推荐

  1. ACM/IOI 历年国家集训队论文集和论文算法分类整理

    国家集训队1999论文集 陈宏:<数据结构的选择与算法效率--从IOI98试题PICTURE谈起> 来煜坤:<把握本质,灵活运用--动态规划的深入探讨> 齐鑫:<搜索方法 ...

  2. 卡在checking installable status

    npm install卡在checking installable status 笔者在使用NPM过程中经常会用到npm install命令,发现有时候会卡在checking installable ...

  3. Safari 中加载 Flash 使用overflow失效的bug

    在Flash标签中加入参数:wmode=transparent

  4. AsyncLocal<T>与ThreadLocal<T>区别研究

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. vs 基本验证控件使用

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.c ...

  6. JS_高程2.在HTML中使用Javascript(1)

    1.使用<script>元素向HTML页面中插入Javascript HTML4.01中<script>标签有6个属性: (1)async:可选.表示立即下载脚本,不影响页面中 ...

  7. python动态构建类(类似声明)

    对于类实例的动态构建,那是非常的简单.可要在代码中动态的构建类,然后该类还能够被使用,那得多么的强大呀. 在Python中,内建的__builtin__提供了一个type的方法,用该方法可以动态的构建 ...

  8. GMA Round 1 极坐标的愤怒

    传送门 极坐标的愤怒 我也想被积分啊!可是为什么你们从来不知道我的心意!——极坐标 愤怒会夺走理智,哪怕是被迫的也好,请为极坐标方程$r=t$(也写作$ρ=θ$)积分吧. 为了考验你的忠诚,你需要回答 ...

  9. .net core安装及初体验

    .net core安装及初体验 .net core 作为微软的新一代技术,在开发跨平台.微服务等方面有很大的优势,也更贴近现代的编码习惯.在2.0版发布很久以后,近期终于决定进行学习和体验. 安装 作 ...

  10. golang 对结构体进行格式化输出

    可以使用 `return fmt.Sprintf("%+v", *conf) ` 来打印结构体,包括结构体的key值.但是由于结构体内容较多,都在一行,所以希望可以格式化输出结构体 ...