赞
踩
市场上有几款比较好的开源库供使用,比如PyWebSocket,WebSocket-Node, LibWebSockets等,这些库文件已经实现了WebSocket数据包的封装和解析,我们可以调用这些接口减少工作量。
1. PyWebSocket
PyWebSocket采用Python语言编写,可以很好的跨平台,扩展起来也比较简单,目前WebKit采用它搭建WebSocket服务器来做LayoutTest,参见http://code.google.com/p/pywebsocket/
2.WebSocket-Node
WebSocket-Node采用JavaScript语言编写,这个库是建立在nodejs之上的,参见https://github.com/Worlize/Websocket-Node
3. LibWebSockets
LibWebSockets采用C/C++语言编写,可定制化的力度更大,从TCP监听开始到封包的完成我们都可以参与编程。参见git://git.warmcat.com/libwebsockets
4.Netty
采用了 Netty 中的 NIO 来构建 WebSocket 后端,参见:https://github.com/netty/netty
一.下面介绍一下用Netty搭建WebSocket服务器
1.WebsocketChatServer .java
- package com.waylau.netty.demo.websocketchat;
-
- import io.netty.bootstrap.ServerBootstrap;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.nio.NioServerSocketChannel;
-
- /**
- * Websocket 聊天服务器-服务端
- *
- * @author waylau.com
- * @date 2015-3-7
- */
- public class WebsocketChatServer {
-
- private int port;
-
- public WebsocketChatServer(int port) {
- this.port = port;
- }
-
- public void run() throws Exception {
-
- EventLoopGroup bossGroup = new NioEventLoopGroup();
- EventLoopGroup workerGroup = new NioEventLoopGroup();
- try {
- ServerBootstrap b = new ServerBootstrap();
- b.group(bossGroup, workerGroup)
- .channel(NioServerSocketChannel.class) // (3)
- .childHandler(new WebsocketChatServerInitializer()) //处理初始化类
- .option(ChannelOption.SO_BACKLOG, 128)
- .childOption(ChannelOption.SO_KEEPALIVE, true); // 保持长连接
-
- System.out.println("WebsocketChatServer 启动了" + port);
-
- // 绑定端口,开始接收进来的连接
- ChannelFuture f = b.bind(port).sync(); // (7)
-
- // 等待服务器 socket 关闭 。
- // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
- f.channel().closeFuture().sync();
-
- } finally {
- workerGroup.shutdownGracefully();
- bossGroup.shutdownGracefully();
-
- System.out.println("WebsocketChatServer 关闭了");
- }
- }
-
- public static void main(String[] args) throws Exception {
- int port;
- if (args.length > 0) {
- port = Integer.parseInt(args[0]);
- } else {
- port = 8080;
- }
- new WebsocketChatServer(port).run();
- }
- }
2.服务端 ChannelInitializer
- package com.waylau.netty.demo.websocketchat;
-
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelPipeline;
- import io.netty.channel.socket.SocketChannel;
- 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;
-
- /**
- * 服务端 ChannelInitializer
- *
- * @author
- * @date 2015-3-13
- */
- public class WebsocketChatServerInitializer extends
- ChannelInitializer<SocketChannel> { //1
-
- @Override
- public void initChannel(SocketChannel ch) throws Exception {//2
- 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());
- }
- }
3.处理TextWebSocketFrame
- package com.waylau.netty.demo.websocketchat;
-
-
- 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;
-
- /**
- * 处理TextWebSocketFrame
- *
- * @author
- * 2015年3月26日
- */
- public class TextWebSocketFrameHandler extends
- SimpleChannelInboundHandler<TextWebSocketFrame> {
-
- public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
-
- @Override
- protected void channelRead0(ChannelHandlerContext ctx,
- TextWebSocketFrame msg) throws Exception { // 读取数据并转发
- Channel incoming = ctx.channel();
- for (Channel channel : channels) {
- if (channel != incoming){
- channel.writeAndFlush(new TextWebSocketFrame(msg.text()));
- } else {
- channel.writeAndFlush(new TextWebSocketFrame(msg.text()));
- }
- }
- }
-
- @Override
- public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // 连接时调用
- Channel incoming = ctx.channel();
-
- // Broadcast a message to multiple Channels
- channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 加入"));
-
- channels.add(incoming);
- System.out.println("Client:"+incoming.remoteAddress() +"加入");
- }
-
- @Override
- public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // 移除时调用
- Channel incoming = ctx.channel();
-
- // Broadcast a message to multiple Channels
- channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 离开"));
-
- System.out.println("Client:"+incoming.remoteAddress() +"离开");
-
- // A closed Channel is automatically removed from ChannelGroup,
- // so there is no need to do "channels.remove(ctx.channel());"
- }
-
- @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 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://192.169.1.101: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 οnsubmit="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="发送消息" οnclick="send(this.form.message.value)">
- <input type="button" οnclick="javascript:document.getElementById('responseText').value=''" value="清空聊天记录">
- </form>
- <br>
- <br>
- </body>
- </html>
点击下载源码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。