• WebSocket集成XMPP网页即时通讯1:Java Web Project服务端/客户端Jetty9开发初探


    Web 应用的信息交互过程通常是客户端通过浏览器发出一个请求,服务器端接收和审核完请求后进行处理并返回结果给客户端,然后客户端浏览器将信息呈现出来,这种机制对于信息变化不是特别频繁的应用尚能相安无事,但是对于那些实时要求比较高的应用来说,比如说在线游戏、在线证券、设备监控、新闻在线播报、RSS 订阅推送等等,当客户端浏览器准备呈现这些信息的时候,这些信息在服务器端可能已经过时了。所以保持客户端和服务器端的信息同步是实时 Web 应用的关键要素,对 Web 开发人员来说也是一个难题。在 WebSocket 规范出来之前,开发人员想实现这些实时的 Web 应用,不得不采用一些折衷的方案,其中最常用的就是轮询 (Polling) 和 Comet 技术(AJAX)。

    但AJAX有显著缺点:

    1、浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽。

    2、客户端和服务器端的编程实现都比较复杂,在实际的应用中,为了模拟比较真实的实时效果,开发人员往往需要构造两个 HTTP 连接来模拟客户端和服务器之间的双向通讯,一个连接用来处理客户端到服务器端的数据传输,一个连接用来处理服务器端到客户端的数据传输。

    WebSocket API是下一代客户端-服务器的异步通信方法。该通信取代了单个的TCP套接字,使用ws或wss(ssl加密)协议,可用于任意的客户端和服务器程序。WebSocket目前由W3C进行标准化。WebSocket已经受到Firefox 4、Chrome 4、Opera 10.70、Edge以及Safari 5等浏览器的支持。

    WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内(IdleTime)的任意时刻,相互推送信息。WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;XHR受到域的限制,而WebSocket允许跨域通信。

    为方便开发,用了Jetty服务器,在网上很多例子都是基于jetty7.0的。但jetty9.0以后WebSocket的基类代码变化很多,于是自己动手开发,参考jetty官网:

    http://www.eclipse.org/jetty/documentation/current/websocket-jetty.html#jetty-websocket-api

    首先在Eclipse新建一个Dynamic web project

    请自行下载安装jetty,另外需要在Eclipse安装Jetty工具,便于调试。

    工程目录结构:

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
     
     <context-param>
       <param-name>debug</param-name>
       <param-value>false</param-value>
     </context-param>
     
     <session-config>  <!--  10 minutes -->
       <session-timeout>10</session-timeout>
     </session-config>
    
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/wsexample</url-pattern>
    </servlet-mapping>
     
     <welcome-file-list>
       <welcome-file>index.html</welcome-file>
       <welcome-file>index.htm</welcome-file>
       <welcome-file>index.jsp</welcome-file>
       <welcome-file>default.html</welcome-file>
       <welcome-file>default.htm</welcome-file>
       <welcome-file>default.jsp</welcome-file>
     </welcome-file-list>
     
    </web-app>

    ant用惯了,懒得去查maven的dependencies了。

    build.xml  

    jetty.lib.dir、deploy.path请自行修改
    <?xml version="1.0" encoding="UTF-8"?>
    
    <project name="WebSocket" default="compile">
        
        <property name="name" value="ws"/>
        <property environment="env"/>
        <property name="src.dir" value="src"/>
        <property name="web.dir" value="WebContent" />
        <property name="build.dir" location="${web.dir}/WEB-INF/classes"/>
        <property name="jetty.lib.dir" location="D:/Software/jetty93/lib"/>
        <property name="dist.dir" location="dist"/>
        <property name="deploy.path" location="D:/Software/jetty93/webapps"/>
      
        <path id="compile.classpath">
            <fileset dir="${jetty.lib.dir}"/>
        </path>
      
        <target name="init">
            <mkdir dir="${build.dir}"/>
            <mkdir dir="${dist.dir}"/>
        </target>     
      
        <target name="compile" depends="init">
            <javac srcdir="${src.dir}" destdir="${build.dir}" 
                   includeantruntime="false">
                <classpath refid="compile.classpath"/>
            </javac>
            <echo>Compilation completed</echo>
        </target>
      
        <target name="archive" depends="compile">
            <war destfile="${dist.dir}/${name}.war" needxmlfile="false">
                <fileset dir="${web.dir}"/>
            </war>
            <echo>Archive created</echo>
        </target> 
      
        <target name="clean" depends="init">
            <delete dir="${build.dir}"/>
            <delete dir="${dist.dir}"/>
            <echo>Cleaning completed</echo>
        </target>  
        
        <target name="deploy" depends="archive">
            <copy file="${dist.dir}/${name}.war" overwrite="true" 
                  todir="${deploy.path}"/>
            <echo>Archive deployed</echo>
        </target>    
        
    </project>

    index.html

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>你好!websocket</title>
    </head>
    <body>
    hello,WebSocket
    <script src="index.js"></script>
    </body>
    </html>

    index.js

    var ws = new WebSocket("ws://localhost:8080/ws/wsexample");
    
    ws.onopen = function() {
        document.write("WebSocket opened <br>");
        ws.send("Hello Server");
    };
    
    ws.onmessage = function(evt) {
        document.write("Message: " + evt.data);
    };
    
    ws.onclose = function() {
        document.write("<br>WebSocket closed");
    };
    
    ws.onerror = function(err) {
        document.write("Error: " + err);
    };

    其中 ws://localhost:8080/ws/wsexample 是WebSocket 服务器地址,是服务器端的Servelt,通过MyServlet.java实现

    WebSocketServlet 类中 configure(WebSocketServletFactory factory) 用来注册socket处理类和设置连接时长,在这个时长内,保持长连接。

    官网的定义:
    http://www.eclipse.org/jetty/documentation/current/jetty-websocket-server-api.html

    MyServlet.java

    暂不理会HTTP GET请求的处理.

     
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.annotation.WebServlet;
    import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
    import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
    
     
    @WebServlet(name = "MyServlet", urlPatterns = { "/wsexample" })
    public class MyServlet extends WebSocketServlet {
    
        private static final long serialVersionUID = 1L;
    
        @Override
        public void doGet(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            response.getWriter().println("HTTP GET method not implemented.");
        }
    
        @Override
        public void configure(WebSocketServletFactory factory) {
            factory.getPolicy().setIdleTimeout(10000);
            factory.register(MySocket.class);
        }
    }

    MySocket.java 是socket具体处理类,写法在jetty7和jetty9有很大的不同。

    import java.io.IOException;
    import org.eclipse.jetty.websocket.api.Session;
    import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
    import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
    import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
    import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
    import org.eclipse.jetty.websocket.api.annotations.WebSocket;
    
    @WebSocket
    public class MySocket {
    
        Session WebSession;
        @OnWebSocketClose
        public void onClose(int statusCode, String reason) {
            System.out.println("Close: " + reason);
        }
    
        @OnWebSocketError
        public void onError(Throwable t) {
            System.out.println("Error: " + t.getMessage());
        }
    
        //客户端连接
        @OnWebSocketConnect
        public void onConnect(Session session) {
            WebSession = session;
            System.out.println("Connect: " + session.getRemoteAddress().getAddress());
            
            try {
                session.getRemote().sendString("你好!客户端。我是服务端。<br>");
            } catch (IOException e) {
                System.out.println("IO Exception");
            }
        }
    
        //接收到客户端的文本消息
        @OnWebSocketMessage
        public void onMessage(String message) {
            System.out.println("客户端消息: " + message);
            try {
                WebSession.getRemote().sendString("客户端,我收到这条消息了:" + message);
            } catch (IOException e) {
                System.out.println("IO Exception");
            }
        }
    }

    测试一下吧

    客户端运行结果:

    完整源代码下载 : source code

  • 相关阅读:
    Nearest Excluded Points ( 转化思想 +多源BFS )
    Tower Defense (分块+差分的差分+优化空间方法, 主席树做法待补)
    mac 安装 vue环境及遇到的报错
    导出excel数据
    Git安装及gitlab 环境配置
    docker engine dockercompose部署
    python实现比较2个excel
    pytest conftest
    javascript 高阶函数
    jmeter 系统的笔记整理【持续更新】
  • 原文地址:https://www.cnblogs.com/starcrm/p/5133377.html
Copyright © 2020-2023  润新知