java中websocket使用实例解读-亚博电竞手机版

介绍

现在很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出http request,然后由服务器返回最新的数据给客服端的浏览器。

这种传统的http request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而http request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽。

而最比较新的技术去做轮询的效果是comet – 用了ajax。但这种技术虽然可达到全双工通信,但依然需要发出请求。

在 websocket api,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

运行环境:

客户端

实现了websocket的浏览器

chrome supported in version 4
firefox supported in version 4
internet explorer supported in version 10
opera supported in version 10
safari supported in version 5

服务端

依赖

tomcat 7.0.47以上 j2ee7

     org.apache.tomcat       tomcat-websocket-api       7.0.47       provided              javax       javaee-api       7.0       provided   

注意:早前业界没有统一的标准,各服务器都有各自的实现,现在j2ee7的jsr356已经定义了统一的标准,请尽量使用支持最新通用标准的服务器。

详见:

http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html

http://jinnianshilongnian.iteye.com/blog/1909962

我是用的tomcat 7.0.57 java7

必须是tomcat 7.0.47以上

详见:http://www.iteye.com/news/28414

ps:最早我们是用的tomcat 7自带的实现,后来要升级tomcat 8,结果原来的实现方式在tomcat 8不支持了,就只好切换到支持websocket 1.0版本的tomcat了。

主流的java web服务器都有支持jsr365标准的版本了,请自行google。

用nginx做反向代理的需要注意啦,socket请求需要做特殊配置的,切记!

tomcat的处理方式建议修改为nio的方式,同时修改连接数到合适的参数,请自行google!

服务端不需要在web.xml中做额外的配置,tomcat启动后就可以直接连接了。

实现

import com.dooioo.websocket.utils.sessionutils; import org.apache.commons.logging.log; import org.apache.commons.logging.logfactory;  import javax.websocket.*; import javax.websocket.server.pathparam; import javax.websocket.server.serverendpoint;  /**  * 功能说明:websocket处理类, 使用j2ee7的标准  *         切忌直接在该连接处理类中加入业务处理代码  * 作者:liuxing(2014-11-14 04:20)  */ //relationid和usercode是我的业务标识参数,websocket.ws是连接的路径,可以自行定义 @serverendpoint("/websocket.ws/{relationid}/{usercode}") public class websocketendpoint {      private static log log = logfactory.getlog(websocketendpoint.class);      /**      * 打开连接时触发      * @param relationid      * @param usercode      * @param session      */     @onopen     public void onopen(@pathparam("relationid") string relationid,                        @pathparam("usercode") int usercode,                        session session){         log.info("websocket start connecting: "   sessionutils.getkey(relationid, usercode));         sessionutils.put(relationid, usercode, session);     }      /**      * 收到客户端消息时触发      * @param relationid      * @param usercode      * @param message      * @return      */     @onmessage     public string onmessage(@pathparam("relationid") string relationid,                             @pathparam("usercode") int usercode,                             string message) {         return "got your message ("   message   ").thanks !";     }      /**      * 异常时触发      * @param relationid      * @param usercode      * @param session      */     @onerror     public void onerror(@pathparam("relationid") string relationid,                         @pathparam("usercode") int usercode,                         throwable throwable,                         session session) {         log.info("websocket connection exception: "   sessionutils.getkey(relationid, usercode));         log.info(throwable.getmessage(), throwable);         sessionutils.remove(relationid, usercode);     }      /**      * 关闭连接时触发      * @param relationid      * @param usercode      * @param session      */     @onclose     public void onclose(@pathparam("relationid") string relationid,                         @pathparam("usercode") int usercode,                         session session) {         log.info("websocket close connection: "   sessionutils.getkey(relationid, usercode));         sessionutils.remove(relationid, usercode);     }  }

工具类用来存储唯一key和连接

这个是我业务的需要,我的业务是服务器有对应动作触发时,推送数据到客户端,没有接收客户端数据的操作。

import javax.websocket.session; import java.util.map; import java.util.concurrent.concurrenthashmap;  /**  * 功能说明:用来存储业务定义的sessionid和连接的对应关系  *          利用业务逻辑中组装的sessionid获取有效连接后进行后续操作  * 作者:liuxing(2014-12-26 02:32)  */ public class sessionutils {      public static map clients = new concurrenthashmap<>();      public static void put(string relationid, int usercode, session session){         clients.put(getkey(relationid, usercode), session);     }      public static session get(string relationid, int usercode){         return clients.get(getkey(relationid, usercode));     }      public static void remove(string relationid, int usercode){         clients.remove(getkey(relationid, usercode));     }      /**      * 判断是否有连接      * @param relationid      * @param usercode      * @return      */     public static boolean hasconnection(string relationid, int usercode) {         return clients.containskey(getkey(relationid, usercode));     }      /**      * 组装唯一识别的key      * @param relationid      * @param usercode      * @return      */     public static string getkey(string relationid, int usercode) {         return relationid   "_"   usercode;     }  }

推送数据到客户端

在其他业务方法中调用

/**  * 将数据传回客户端  * 异步的方式  * @param relationid  * @param usercode  * @param message  */ public void broadcast(string relationid, int usercode, string message) {     if (telsocketsessionutils.hasconnection(relationid, usercode)) {         telsocketsessionutils.get(relationid, usercode).getasyncremote().sendtext(message);     } else {         throw new nullpointerexception(telsocketsessionutils.getkey(relationid, usercode)   " connection does not exist");     } }

我是使用异步的方法推送数据,还有同步的方法

详见:http://docs.oracle.com/javaee/7/api/javax/websocket/session.html

客户端代码

var websocket = null; var trytime = 0; $(function () {     initsocket();      window.onbeforeunload = function () {         //离开页面时的其他操作     }; });  /**  * 初始化websocket,建立连接  */ function initsocket() {     if (!window.websocket) {         alert("您的浏览器不支持websocket!");         return false;     }      websocket = new websocket("ws://127.0.0.1:8080/websocket.ws/"   relationid   "/"   usercode);      // 收到服务端消息     websocket.onmessage = function (msg) {         console.log(msg);     };      // 异常     websocket.onerror = function (event) {         console.log(event);     };      // 建立连接     websocket.onopen = function (event) {         console.log(event);     };      // 断线重连     websocket.onclose = function () {         // 重试10次,每次之间间隔10秒         if (trytime < 10) {             settimeout(function () {                 websocket = null;                 trytime  ;                 initsocket();             }, 500);         } else {             trytime = 0;         }     };  }

其他调试工具

java实现一个websocket的客户端

依赖:

     org.java-websocket     java-websocket     1.3.0 

代码:

import java.io.ioexception;   import javax.websocket.clientendpoint;   import javax.websocket.onerror;   import javax.websocket.onmessage;   import javax.websocket.onopen;   import javax.websocket.session;    @clientendpoint   public class myclient {       @onopen       public void onopen(session session) {           system.out.println("connected to endpoint: "   session.getbasicremote());           try {               session.getbasicremote().sendtext("hello");           } catch (ioexception ex) {           }       }        @onmessage       public void onmessage(string message) {           system.out.println(message);       }        @onerror       public void onerror(throwable t) {           t.printstacktrace();       }   }
     import java.io.bufferedreader;   import java.io.ioexception;   import java.io.inputstreamreader;   import java.net.uri;   import javax.websocket.containerprovider;   import javax.websocket.deploymentexception;   import javax.websocket.session;   import javax.websocket.websocketcontainer;    public class myclientapp {        public session session;        protected void start()                {                websocketcontainer container = containerprovider.getwebsocketcontainer();                string uri = "ws://127.0.0.1:8080/websocket.ws/relationid/12345";               system.out.println("connecting to "   uri);               try {                   session = container.connecttoserver(myclient.class, uri.create(uri));               } catch (deploymentexception e) {                   e.printstacktrace();               } catch (ioexception e) {                   e.printstacktrace();               }                     }       public static void main(string args[]){           myclientapp client = new myclientapp();           client.start();            bufferedreader br = new bufferedreader(new inputstreamreader(system.in));           string input = "";           try {               do{                   input = br.readline();                   if(!input.equals("exit"))                       client.session.getbasicremote().sendtext(input);                }while(!input.equals("exit"));            } catch (ioexception e) {               // todo auto-generated catch block               e.printstacktrace();           }       }   }

chrome安装一个websocket客户端调试

最后

为了统一的操作体验,对于一些不支持websocket的浏览器,请使用socketjs技术做客户端开发。

展开全文
内容来源于互联网和用户投稿,文章中一旦含有亚博电竞手机版的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系亚博电竞手机版删除

最新文章

网站地图