搭建WebSocket服务器与客户端

来源:互联网 发布:java输入流和输出流 编辑:程序博客网 时间:2024/05/29 02:54

市场上有几款比较好的开源库供使用,比如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 extendsChannelInitializer<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 extendsSimpleChannelInboundHandler<TextWebSocketFrame> {public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);@Overrideprotected 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());"    }    @Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception { //         Channel incoming = ctx.channel();System.out.println("Client:"+incoming.remoteAddress()+"在线");}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception { //         Channel incoming = ctx.channel();System.out.println("Client:"+incoming.remoteAddress()+"掉线");}@Overridepublic 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 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>
点击下载源码




0 0
原创粉丝点击