netty websocket协议开发
websocket的好处我们就不用多说了,就是用于解决长连接、服务推送等需要的一种技术。
以下我们来看一个例子:
package com.ming.netty.http.websocket; import java.net.InetSocketAddress; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler; public class WebSocketServer { public static void main(String[] args) {
new WebSocketServer().run("127.0.0.1", 8500);
} public void run(String addr,int port){
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b=new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new WebSocketServerHandlerInitializer()); ChannelFuture f=b.bind(new InetSocketAddress(addr, port)).sync();
System.out.println("启动服务器:"+f.channel().localAddress());
//等等服务器端监听端口关闭
f.channel().closeFuture().sync(); } catch (Exception e) {
e.printStackTrace();
}finally{
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} protected class WebSocketServerHandlerInitializer extends ChannelInitializer<SocketChannel>{ @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(64*1024));
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpRequestHandler("/ws"));
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
pipeline.addLast(new TextWebSocketFrameHandler());
} }
}
package com.ming.netty.http.websocket; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedNioFile; import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URISyntaxException;
import java.net.URL; public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> { private final String wsUri;
private static final File INDEX; // static HTTP request handling operation.
static {
URL location = HttpRequestHandler.class.getProtectionDomain().getCodeSource().getLocation();
try {
String path = location.toURI() + "WebSocketClient.html";
path = !path.contains("file:") ? path : path.substring(5);
INDEX = new File("D:\\javaPro\\workspace\\NettyTest\\resources\\WebsocketChatClient.html");
} catch (URISyntaxException e) {
throw new IllegalStateException("Unable to locate WebsocketChatClient.html", e);
}
} public HttpRequestHandler(String wsUri) {
this.wsUri = wsUri;
} @Override
protected void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
channelRead(ctx,request); } public void channelRead(ChannelHandlerContext ctx, FullHttpRequest request)
throws Exception {
if (wsUri.equalsIgnoreCase(request.getUri())) {
ctx.fireChannelRead(request.retain());
} else {
if (HttpHeaders.is100ContinueExpected(request)) {
send100Continue(ctx);
} RandomAccessFile file = new RandomAccessFile(INDEX, "r");
HttpResponse response = new DefaultHttpResponse(
request.getProtocolVersion(), HttpResponseStatus.OK);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE,
"text/html; charset=UTF-8"); boolean keepAlive = HttpHeaders.isKeepAlive(request);
if (keepAlive) {
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, file.length());
response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}
ctx.write(response); if (ctx.pipeline().get(SslHandler.class) == null) {
ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
} else {
ctx.write(new ChunkedNioFile(file.getChannel()));
}
ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if (!keepAlive) {
future.addListener(ChannelFutureListener.CLOSE);
} file.close();
}
} private static void send100Continue(ChannelHandlerContext ctx) {
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
ctx.writeAndFlush(response);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
Channel incoming = ctx.channel();
System.out.println("Client:" + incoming.remoteAddress() + "异常"); // 当出现异常就关闭连接
cause.printStackTrace();
ctx.close();
} }
package com.ming.netty.http.websocket; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor; public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println("Client:" + incoming.remoteAddress() + "在线");
} @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println("Client:" + incoming.remoteAddress() + "掉线");
} @Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
for (Channel channel : channels) {
channel.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 加入"));
}
channels.add(ctx.channel());
System.out.println("Client:" + incoming.remoteAddress() + "加入");
} @Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
for (Channel channel : channels) {
channel.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 离开"));
}
System.out.println("Client:" + incoming.remoteAddress() + "离开");
channels.remove(ctx.channel());
} @Override
protected void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
Channel incoming = ctx.channel();
for (Channel channel : channels) {
if (channel != incoming) {
//channel.writeAndFlush(new TextWebSocketFrame("[" + incoming.remoteAddress() + "]" + msg.text()));
} else {
//返送给指定的
channel.writeAndFlush(new TextWebSocketFrame("[服务器端返回]:" + msg.text())); //output current message to context.
StringBuffer sb = new StringBuffer();
sb.append(incoming.remoteAddress()).append("->").append(msg.text());
System.out.println(sb.toString());
}
} } @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Channel incoming = ctx.channel();
System.out.println("Client:" + incoming.remoteAddress() + "异常");
// 当出现异常就关闭连接
cause.printStackTrace();
ctx.close();
} }
<!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://127.0.0.1:8500/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 www.waylau.com">
<input type="button" value="发送消息" onclick="send(this.form.message.value)">
<input type="button" onclick="javascript:document.getElementById('responseText').value=''" value="清空聊天记录">
</form>
<br>
<br> </body>
</html>
运行服务器,然后在浏览器输入:127.0.0.1:8500 就可以看见一个简单的聊天室效果了.
netty websocket协议开发的更多相关文章
- WebSocket协议开发
一直以来,网络在很大程度上都是围绕着HTTP的请求/响应模式而构建的.客户端加载一个网页,然后直到用户点击下一页之前,什么都不会发生.在2005年左右,Ajax开始让网络变得更加动态了.但所有的HTT ...
- netty(4)高级篇-Websocket协议开发
一.HTTP协议的弊端 将HTTP协议的主要弊端总结如下: (1) 半双工协议:可以在客户端和服务端2个方向上传输,但是不能同时传输.同一时刻,只能在一个方向上传输. (2) HTTP消息冗长:相比于 ...
- 真正实现Netty私有协议开发
首先<Netty权威指南>私有协议开发那一章的样例代码是编译不通过的(但是这丝毫不影响本书的价值)处理方案可以参考:http://www.itnose.net/detail/6112870 ...
- netty高级篇(3)-HTTP协议开发
一.HTTP协议简介 应用层协议http,发展至今已经是http2.0了,拥有以下特点: (1) CS模式的协议 (2) 简单 - 只需要服务URL,携带必要的请求参数或者消息体 (3) 灵活 - 任 ...
- dotnet core 开发无缝兼容Http和Websocket协议的接口服务
在应用接口开发中往往要针对不同协义开发相应的代理服务,但对于Websocket和http这两种协议来说就有些不同,从实现上来看Websocket可以说是Http的升级子协议, 两者在协议处理上基本一致 ...
- Netty WebSocket 开发
代码: Server package netty.protocol.websocket.server; import io.netty.bootstrap.ServerBootstrap; impor ...
- workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)
workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...
- 八问WebSocket协议:为你快速解答WebSocket热门疑问
一.引言 WebSocket是一种比较新的协议,它是伴随着html5规范而生的,虽然还比较年轻,但大多主流浏览器都已经支持.它使用方面.应用广泛,已经渗透到前后端开发的各种场景中. 对http一问一答 ...
- WebSocket协议 8 问
WebSocket是一种比较新的协议,它是伴随着html5规范而生的,虽然还比较年轻,但大多主流浏览器都已经支持.它使用方面.应用广泛,已经渗透到前后端开发的各种场景中. 对http一问一答中二式流程 ...
随机推荐
- SQL多表连接
在KS系统中分配好权限以后,在用户登录的时候就要通过用户查到角色,通过角色查到界面,界面又属于某个菜单,一共要查4个表.并且不能有重复的记录这个时候就用到了SQL的内连接.SQL的多表连接很方便,以前 ...
- iOS多线程编程Part 3/3 - GCD
前两部分介绍了NSThread.NSRunLoop和NSOperation,本文聊聊2011年WWDC时推出的神器GCD.GCD: Grand Central Dispatch,是一组用于实现并发编程 ...
- NGUI3.5系列教程之 UILabel
此NGUI版本为:3.5.1 NGUI 的UILabel脚本下的文字框可以用BBCode设置:[b]Bold[/b] 粗体 [i]italic[/i] 斜体 [u]underline[/u]下划线 [ ...
- 屌丝IT男
偶尔翻到豆瓣里一篇对中国屌丝的批评,突然想到当年美国那个垮掉的一代,吸毒,淫乱,绝望的生存,而如今我们苦逼的80后自诩为屌丝的时候,也不想想每一个堕落的时代还是有牛逼的人存在,中国的大学,绝大部分在逃 ...
- Oracle 新建序列值
create sequence MSG_OUTBOX_ID_SEQ minvalue maxvalue start increment cache ;
- 送给那些喜欢myeclipse黑色主题但是又不知道怎么配色的人
设置MyEclipse黑色主题背景 1. 下载 http://eclipsecolorthemes.org/ 看哪个合适直接点击进入, 下载右边的epf 2. 下载完成...打开myeclipse. ...
- cookieContainer应用
PublicSharedFunctionGetCookiesSetByPage(ByVal strUrl AsString,ByVal cookieToProvide AsString)AsIEnum ...
- Log4Net 日志配置[附带源码]
前述 园子里有许多人对log4net这款开源的日志记录控件有很多介绍.在这里个人再做一次总结,希望对以后有所帮助,需要的时候可以直接使用,减少查阅资料的时间.利用log4net可以方便地将日志信息记录 ...
- 【BZOJ】【3295】【CQOI2011】动态逆序对
树套树 Orz zyf神犇 时光倒流……逆序处理,将删点改为加点,动态维护序列. 由于是动态,要加点,所以用树状数组:同时又需要求序列中求比当前元素大/小的元素个数,所以要用平衡树. 所以方法就是在树 ...
- JSP/SERVLET重定向技术综述
1.RequestDispatcher.forward() 是在服务器端起作用,当使用forward()时,Servlet engine传递HTTP请求从当前的Servlet or JSP到另外一个S ...