`
zzc1684
  • 浏览: 1224425 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

用jetty搭建websocket服务并与ie78兼容的方法

阅读更多

用jetty搭建websocket服务并与ie78兼容的方法

jetty8中已经自带有websocket功能,所以我们可以很方便搭建一个自己的websocket服务。

源程序:http://sdrv.ms/N5BuKw

启动类:org.noahx.websocket.WebSocketServer

访问地址:http://127.0.0.1:8085/test.html

1、外部依赖包如下(maven)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.noahx</groupId>
    <artifactId>ws-test</artifactId>
    <version>1.0</version>

    <properties>
        <jetty.version>8.1.5.v20120716</jetty.version>
        <slf4j.version>1.6.1</slf4j.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>${jetty.version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-websocket</artifactId>
            <version>${jetty.version}</version>
        </dependency>

    </dependencies>

</project>

2、搭建的websocket server,写一个服务器启动类

 WebSocketServer

package org.noahx.websocket;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.resource.FileResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;

/**
 * Created with IntelliJ IDEA.
 * User: noah
 * Date: 8/8/12
 * Time: 5:10 PM
 * To change this template use File | Settings | File Templates.
 */
public class WebSocketServer {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private Server server;

    private FlashPolicyServer fpServer;

    private int port;

    public static void main(String[] args) {

        WebSocketServer server = new WebSocketServer(8085);
        server.start();

    }

    public WebSocketServer(int port) {
        this.port=port;
    }

    public void start(){

        fpServer=new FlashPolicyServer(10843);
        fpServer.start();
        server = new Server(port);

        MyWebSocketHandler myWebSocketHandler = new MyWebSocketHandler();

        URL url=this.getClass().getClassLoader() .getResource("org/noahx/websocket/http");

        ResourceHandler resourceHandler=new ResourceHandler();
        try {
            resourceHandler.setBaseResource(new FileResource(url));
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (URISyntaxException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        myWebSocketHandler.setHandler(resourceHandler);

        server.setHandler(myWebSocketHandler);

        try {
            server.start();
        server.join();
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
    }
}

 

websocket服务端口我设置的为8085。通过向jetty server中加入WebSocketHandler就可以提供websocket服务了。由于WebSocketHandler是 HandlerWrapper的子类,所以这个handler中还可以再加入一个ResourceHandler。这样就可以在一个端口上同时提供 websocket与http服务。ResourceHandler指向了类路径org/noahx/websocket/http下,这个包下的所有资 源都将可以发布为web资源给http请求。

3、开发MyWebSocketHandler与MyWebSocket

MyWebSocketHandler与MyWebSocket

package org.noahx.websocket;

import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Timer;

/**
 * Created with IntelliJ IDEA.
 * User: noah
 * Date: 8/8/12
 * Time: 5:16 PM
 * To change this template use File | Settings | File Templates.
 */
public class MyWebSocketHandler extends WebSocketHandler {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {

        if (logger.isDebugEnabled()) {
            logger.debug("url=" + request.getRequestURL() + ",protocol=" + protocol);
        }

        return new MyWebSocket();
    }

    public class MyWebSocket implements WebSocket.OnTextMessage {

        private Logger logger = LoggerFactory.getLogger(this.getClass());

        private Connection connection;

        private Timer timer = new Timer();


        @Override
        public void onMessage(String data) {
            if (logger.isDebugEnabled()) {
                logger.debug("onMessage");
            }
        }

        @Override
        public void onOpen(Connection connection) {
            if (logger.isDebugEnabled()) {
                logger.debug("onOpen");
            }
            this.connection = connection;

            timer.schedule(new MemTask(this), 0, 500);
        }

        @Override
        public void onClose(int closeCode, String message) {
            if (logger.isDebugEnabled()) {
                logger.debug("onClose");
            }
            timer.cancel();
        }

        public void send(String msg) {
            try {
                if (logger.isDebugEnabled()) {
                    logger.debug("send:" + msg);
                }
                connection.sendMessage(msg);
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
                timer.cancel();
            }
        }

    }
}

 

doWebSocketConnect中实现doWebSocketConnect方法,返回我们需要的WebSocket对象。
doWebSocketConnect方法中可以取到请求的url,所以可以当做分发器,通过url的不同分发到不同WebSocket。

如:ws://127.0.0.1:8085/ws1与ws://127.0.0.1:8085/ws2

MyWebSocket所实现的内容是以每500毫秒的速度,向浏览器发送0-100的随机数(注意这里是由服务器主动推送)。

MemTask

package org.noahx.websocket;

import java.util.Random;
import java.util.TimerTask;

/**
 * Created with IntelliJ IDEA.
 * User: noah
 * Date: 8/8/12
 * Time: 5:31 PM
 * To change this template use File | Settings | File Templates.
 */
public class MemTask extends TimerTask {

    private MyWebSocketHandler.MyWebSocket myWebSocket;

    public MemTask(MyWebSocketHandler.MyWebSocket myWebSocket) {
        this.myWebSocket = myWebSocket;
    }

    @Override
    public void run() {
        myWebSocket.send("" +new Random().nextInt(100));

    }

}

 

取随机数的任务类

4、开发前台javascript客户机(test.html) 

使用到了以下内容:

web-socket-js,https://github.com/gimite/web-socket-js/
就是这个解决了不支持html5的websocket的浏览器也可以调用websocket的问题。web-socket-js会自动判断是不是支持 html5的websocket,如果支持没有什么区别。如果发现不支持将通过Flash自动调用websocket来做socket的中转。

highcharts,http://www.highcharts.com/
这个是通过纯javascript(jquery)来绘制图表的js图表框架。来配合websocket,做到实时的动态图表。

test.html

<html>
<head>
    <title></title>

    <script type="text/javascript" src="swfobject.js"></script>
    <script type="text/javascript" src="web_socket.js"></script>

    <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
    <script src="hc/highcharts.js"></script>
    <script src="hc/modules/exporting.js"></script>


</head>
<body>

<script type="text/javascript">

    var host = window.location.host.split(":")[0];


    WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";
    WEB_SOCKET_DEBUG = false;
    try {
        WebSocket.loadFlashPolicyFile("xmlsocket://" + host + ":10843");
    } catch (e) {
    }

    var ws;

    function init(series) {

        ws = new WebSocket("ws://" + host + ":8085/");

        ws.onopen = function () {
            output("onOpen");
        };
        ws.onmessage = function (e) {
            var dStr = e.data;
            outputmem(dStr);

            var x = (new Date()).getTime(), // current time
                    y = parseInt(dStr);
            series.addPoint([x, y], true, true);
        };
        ws.onclose = function () {
            output("onClose");
        };
        ws.onerror = function () {
            output("onError");
        };

    }

    function outputmem(str) {
        var mem = document.getElementById("mem");
        mem.innerHTML = str;
    }

    function output(str) {

        var log = document.getElementById("log");

        var escaped = str.replace(/&/, "&amp;").replace(/</, "&lt;").
                replace(/>/, "&gt;").replace(/"/, "&quot;"); // "
        log.innerHTML = escaped + "<br>" + log.innerHTML;
    }

    $(function () {
        $(document).ready(function () {
            Highcharts.setOptions({
                global:{
                    useUTC:false
                }
            });

            var chart;
            chart = new Highcharts.Chart({
                chart:{
                    renderTo:'container',
                    type:'spline',
                    marginRight:10,
                    events:{
                        load:function () {

                            // set up the updating of the chart each second
                            var series = this.series[0];
                            init(series);
                        }
                    }
                },
                title:{
                    text:'WebSocket random data'
                },
                xAxis:{
                    type:'datetime',
                    tickPixelInterval:150
                },
                yAxis:{
                    title:{
                        text:'Value'
                    },
                    plotLines:[
                        {
                            value:0,
                            width:1,
                            color:'#808080'
                        }
                    ]
                },
                tooltip:{
                    formatter:function () {
                        return '<b>' + this.series.name + '</b><br/>' +
                                Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
                                Highcharts.numberFormat(this.y, 2);
                    }
                },
                legend:{
                    enabled:false
                },
                exporting:{
                    enabled:false
                },
                series:[
                    {
                        name:'Zero data',
                        data:(function () {
                            var data = [],
                                    time = (new Date()).getTime(),
                                    i;

                            for (i = -19; i <= 0; i++) {
                                data.push({
                                    x:time + i * 1000,
                                    y:0
                                });
                            }
                            return data;
                        })()
                    }
                ]
            });
        });

    });

</script>

<div id="mem"></div>

<div id="log"></div>


<div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>

</body>
</html>

 

原理是通过web-socket-js建立与服务器的websocket连接,服务器发现连接后会主动推送数据给浏览器。

收到服务器推送过来的数据会触发onmessage,这时在onmessage中对图表进行绘制。从而达到效果。

*5、Flash Policy Server的配置

ie78可以使用websocket的关键。web-socket-js会调用flash请求websocket。

flash请求websocket也有一个前提。flash会检查安全策略文件(xml)是否允许它这样做。默认flash会请求相同host的 843端口,发送policy-file-request请求,这时返回正常的安全策略时,websocket才可以正常使用。当然我们也可以通过 WebSocket.loadFlashPolicyFile(方法重新指定策略文件url。样例是指向了10843端口,因为如果监听<1000 的端口需要root权限,所以内嵌Java版的Flash Policy Server端口为10843。

但还是建议不要手动指定WebSocket.loadFlashPolicyFile,而是用843。因为flash总是先会从843找,如果找不到再从websocket端口找(8085)。所以如果设置其它url了会影响加载速度。

Flash Policy的资料可以参考:http://www.adobe.com/devnet/flashplayer/articles/socket_policy_files.html
里面提供了一个flashpolicyd_v0.6程序,可以做Flash Policy Server,但不是java实现的。

我也写了一个Flash Policy Server,java版的

FlashPolicyServer

package org.noahx.websocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

/**
 * Created with IntelliJ IDEA.
 * User: noah
 * Date: 8/8/12
 * Time: 10:05 PM
 * To change this template use File | Settings | File Templates.
 */
public class FlashPolicyServer {

    private ServerSocket serverSocket;

    private static Thread serverThread;

    private int port;

    private static boolean listening = true;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public FlashPolicyServer() {
        this(843);
    }

    public FlashPolicyServer(int port) {
        this.port = port;
    }

    public void start() {

        try {
            serverThread = new Thread(new Runnable() {
                public void run() {
                    try {

                        logger.info("FlashPolicyServer: Starting...");
                        serverSocket = new ServerSocket(port);

                        while (listening) {
                            final Socket socket = serverSocket.accept();

                            Thread t = new Thread(new Runnable() {
                                public void run() {
                                    try {

                                        if (logger.isDebugEnabled()) {
                                            logger.debug("FlashPolicyServer: Handling Request...");
                                        }

                                        socket.setSoTimeout(10000);

                                        InputStream in = socket.getInputStream();

                                        byte[] buffer = new byte[23];

                                        if (in.read(buffer) != -1 && (new String(buffer, "ISO-8859-1")).startsWith("<policy-file-request/>")) {

                                            if (logger.isDebugEnabled()) {
                                                logger.debug("PolicyServerServlet: Serving Policy File...");
                                            }

                                            OutputStream out = socket.getOutputStream();


                                            byte[] bytes = ("<?xml version=\"1.0\"?>\n" +
                                                    "<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\n" +
                                                    "<cross-domain-policy> \n" +
                                                    "   <site-control permitted-cross-domain-policies=\"master-only\"/>\n" +
                                                    "   <allow-access-from domain=\"*\" to-ports=\"*\" />\n" +
                                                    "</cross-domain-policy>").getBytes("ISO-8859-1");

                                            out.write(bytes);

                                            out.write(0x00);

                                            out.flush();
                                            out.close();
                                        } else {
                                            logger.warn("FlashPolicyServer: Ignoring Invalid Request");
                                            logger.warn("  " + (new String(buffer)));
                                        }

                                    } catch (SocketException e) {
                                        logger.error(e.getMessage(), e);
                                    } catch (IOException e) {
                                        logger.error(e.getMessage(), e);
                                    } finally {
                                        try {
                                            socket.close();
                                        } catch (Exception ex2) {
                                        }
                                    }
                                }
                            });
                            t.start();
                        }
                    } catch (IOException ex) {
                        logger.error("PolicyServerServlet Error---");
                        logger.error(ex.getMessage(), ex);
                    }
                }

            });
            serverThread.start();
        } catch (Exception ex) {
            logger.error("PolicyServerServlet Error---");
            logger.error(ex.getMessage(), ex);
        }

    }

    public void stop() {
        logger.info("FlashPolicyServer: Shutting Down...");

        if (listening) {
            listening = false;
        }

        if (!serverSocket.isClosed()) {
            try {
                serverSocket.close();
            } catch (Exception ex) {
            }
        }
    }
}

 

这样就可以和websocket server整合在一起。

安全策略文件的样例格式:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
   <site-control permitted-cross-domain-policies="master-only"/>
   <allow-access-from domain="*" to-ports="*" />
</cross-domain-policy>

 

6、websocket展望

继ajax后websocket会给界面带来更快更好的交互效果与体验,伴随移动市场的壮大websocket也将有可能成为标准的api协议。

框架介绍:

AS3WebSocket,https://github.com/Worlize/AS3WebSocket
提供给ActiveScript3使用的websocket框架

jWebSocket,http://jwebsocket.org/
有服务器与客户端,高一级别websocket框架,提供了对基础websocket的扩展,如jsonSocket,xmlSocket,cvsSocket

kaazing(商业),http://kaazing.com/
商业级整套html5与websocket解决方案,效果最好,可惜是商业的

分享到:
评论

相关推荐

    jetty实现websocket功能

    6. **启动和停止**: 启动Jetty服务器并监听WebSocket连接,然后在适当的时候关闭服务器。启动服务器通常调用`server.start()`,而关闭则调用`server.stop()`。 在`jettysocket`这个压缩包中,可能包含了一些示例...

    基于jetty8 websocket的例子

    在本文中,我们将深入探讨如何使用Jetty 8实现WebSocket技术来构建一个实时通信的聊天工具。WebSocket协议是一种在客户端和服务器之间建立长连接...通过将WebSocket与数据库操作相结合,可以构建更复杂的实时应用程序。

    jetty-websocket-7.6.10.v20130312.jar

    java运行依赖jar包

    用jetty8.0写的websocket实现的简单聊天程序

    在使用Jetty实现WebSocket聊天程序时,我们需要创建一个继承自`org.eclipse.jetty.websocket.WebSocket.OnTextMessage`的类,重写`onOpen`、`onClose`、`onMessage`等方法。`onOpen`在连接建立时调用,`onClose`在...

    jetty html5 websocket服务器

    为了在Jetty服务器上部署WebSocket应用,可以将WebSocket端点类打包到一个Java Web应用程序中,并通过Jetty的Web应用部署机制(如`web.xml`配置或使用Jetty的`Server`和`WebAppContext`类)进行部署。 标签"jetty...

    websocket+tomcat+jetty+netty

    与Tomcat相比,Jetty的启动速度更快,内存占用更少,对于小型和嵌入式项目特别适用。Jetty对WebSocket的支持非常全面,它实现了WebSocket API,使得开发者可以方便地在Jetty服务器上构建WebSocket应用。 Netty则是...

    webSocketDemo2支持ie浏览器

    在实现WebSocket与IE9的兼容性时,通常需要借助Flash技术,因为IE9不原生支持WebSocket。Flash的Socket API可以模拟WebSocket的双向通信,提供了一种在旧版IE浏览器上实现WebSocket功能的途径。因此,"WebSocketDemo...

    Jmeter-WebSocket测试插件&依赖包

    Jmeter实现WebSocket接口的所必须的插件包 1、org.eclipse.jetty.http_9.1.1.v20140108.jar 2、org.eclipse.jetty.io_9.1.1.v20140108.jar 3、org.eclipse.jetty.util_9.1.1.v20140108.jar 4、org.eclipse.jetty....

    websocket-api-9.4.11.v20180605-API文档-中文版.zip

    赠送jar包:websocket-api-9.4.11.v20180605.jar...使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    jetty-websocket

    jetty-websocket

    Spring-Boot-Jetty-WebSocket-Example:如何使用Spring Boot配置Jetty WebSocket的基本示例

    在本文中,我们将深入探讨如何使用Spring Boot与Jetty服务器集成来实现WebSocket通信。WebSocket是一种在客户端和服务器之间建立持久连接的协议,允许双向实时数据传输。Spring Boot简化了Java应用的开发,包括...

    jetty-websocket-api-9.0.3-8.el7.noarch.rpm

    官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装

    websocket-api-9.4.43.v20210629-API文档-中文版.zip

    赠送jar包:websocket-api-9.4.43.v20210629.jar...使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    jetty-websocket-example:使用嵌入式Jetty设置WebSocket服务的示例代码

    使用Java SE的Websocket的示例与其使用Java EE及其附带的所有功能,不如使用Java EE,而不是WebSocket的一种较小的实现方式,可能是针对独立程序或嵌入式应用程序的。 该示例将显示使码头服务器运行,为websocket...

    Java_嵌入式Jetty WebSocket示例.zip

    而`embedded-jetty-websocket-examples_repo-moved.zip`则可能是一个包含实际源代码的归档文件,用于演示如何在Java项目中嵌入Jetty服务器并实现WebSocket功能。 让我们深入探讨一下使用Jetty实现WebSocket的基本...

    基于websocket和jetty8的聊天室demo

    - `ChatServerEndpoint.java`: WebSocket服务端点类,实现WebSocket的生命周期方法。 - `ChatServlet.java`: WebSocketServlet,负责处理WebSocket连接请求。 - `web.xml`: Jetty的配置文件,声明和配置...

    embedded-jetty-websocket-examples:嵌入式Jetty WebSocket示例

    您可以将2种与Jetty一起使用的API,本机WebSocket API和javax.websocket API。 项目:javax.websocket-example 演示如何使用javax.websocket API创建WebSocket客户端或WebSocket服务器。 项目:native-jetty-...

    Java Web Project开发WebSocket服务端/客户端

    客户端则需要创建一个继承自`org.eclipse.jetty.websocket.client.WebSocketClient`的类,并实现`org.eclipse.jetty.websocket.api.RemoteEndpoint`接口,用以发送和接收消息。 在项目中,我们可以看到`.project`...

    终于调通了jetty8下的websocket的应用

    总之,通过Jetty 8实现WebSocket应用需要理解WebSocket协议的工作原理,实现WebSocket服务器和客户端的接口,并在Jetty服务器上进行正确的配置。调试过程中,要注意网络通信的细节,如连接状态、消息传输等。通过...

    Spring4+WebSocket+Socket+STOMP+Jetty构建示例

    在本示例中,我们将探讨如何使用Spring框架的版本4结合WebSocket、Socket、STOMP协议以及Jetty服务器来构建一个实时通信的应用。WebSocket是一种在浏览器和服务器之间建立长连接的协议,极大地提高了数据传输效率,...

Global site tag (gtag.js) - Google Analytics