代码:

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. BZOJ2240 : ural1676 Mortal Combat

    首先如果最大匹配不足$n$个那么显然每条边都不可能在匹配为$n$的方案中. 对于一条边$(u,v)$,如果它可能在最大匹配中,有两种情况: $1.(u,v)$是当前方案的匹配边. $2.$可以沿着$( ...

  2. ios程序中存储的回忆

    可编程序中的存储区域基本上分为:静态存储区,栈区,堆区,代码区. 1.静态存储区(全局存储区):该块内存在程序编译期间就已经分配好,并且在程序运行期间都一直存在,主要用于存储静态数据,全局数据和常量. ...

  3. [原创]浅谈IT人如何做理财规划

    [原创]浅谈IT人如何做理财规划 鱼哥博客上多数写的是技术和管理相关,但很少有理财等话题,今天抽空来谈谈IT人如何做理财规划,如果要想学习理财,我想很有名的“标准普尔家庭资产象限图”上值得每个学习和理 ...

  4. 利用exif.js解决手机上传竖拍照片旋转90\180\270度问题

    原文:https://blog.csdn.net/linlzk/article/details/48652635/ html5+canvas进行移动端手机照片上传时,发现ios手机上传竖拍照片会逆时针 ...

  5. Android的Databinding-数据、Map绑定

    本节主要说Collection的字符串数组.List.SparseArray.Map的绑定.先看看xml的布局. <layout xmlns:android="http://schem ...

  6. MySQL DBA工作角色和职责介绍

    MySQL DBA分架构DBA,运维DBA和开发DBA三种角色,职责介绍如下:

  7. Java操作Linuxshell并且获取返回值

    /** * */package com.king.weixin.util;import java.io.BufferedReader;import java.io.InputStream;/*** @ ...

  8. 【纵谭 Python】系列直播(持续更新)

    老周最近录了一些跟 Python 有关的直播,可以在“一直播”中搜索 ID 号 139251129 关注,也可以在微博中查看,反正都一样,同步的. 第一集:简单胡扯一下相关环境搭建.安装 Python ...

  9. 【.NET 深呼吸】.net core 中的轻量级 Composition

    记得前面老周写过在.net core 中使用 Composition 的烂文.上回老周给大伙伴们介绍的是一个“重量级”版本—— System.ComponentModel.Composition.应该 ...

  10. Python禁用GC优化性能

    Python使用的(Garbage Collection, GC)机制是引用计数(Reference Count),其原理是为每一个内存对象进行引用计数,因此当有大量的对象新建或删除时,必须要进行大量 ...