美文网首页Java 杂谈Java进阶之路
WebSocket-服务器到客户端的请求

WebSocket-服务器到客户端的请求

作者: elijah777 | 来源:发表于2019-05-20 22:41 被阅读0次

    WebSocket通信

    引言:

    WebSocket主要用过后端向前端访问,这样避免了一些项目上执行时间比较久的,不必前端一直请求数据,定时刷新什么的。

    比如说,需要实现一个等待时间比较久的功能,提交某类单子,或者充值支付等,不方边使用异步操作,需要实时返回消息给用户,可以选用,也可以用百分比的形式返回后端执行的情况。

    一、WebSocket 简介

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

    WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

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

    现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

    HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

    二、WebSocket客户端

    websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。

    在websocket中有两个方法: websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。

    在websocket中有两个方法:

    1. send() 向远程服务器发送数据
    2. close() 关闭该websocket链接

    websocket同时还定义了几个监听函数

    1. onopen 当网络连接建立时触发该事件
    2. onerror 当网络发生错误时触发该事件
    3. onclose 当websocket被关闭时触发该事件
    4. onmessage 当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件。

    三、代码实战

    请求与接收消息的页面

     var socket;
    if(typeof(WebSocket) == "undefined") {
     console.log("您的浏览器不支持WebSocket");
    }else{
    ​
     var url='ws://'+window.location.host+'/websocket/${cid}';
    ​
     debugger;
     console.log("您的浏览器支持WebSocket");
     //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
     //等同于socket = new WebSocket("ws://localhost:8083/checkcentersys/websocket/20");
     socket = new WebSocket(url);
     //打开事件
     socket.onopen = function() {
     console.log("Socket 已打开");
     //socket.send("这是来自客户端的消息" + location.href + new Date());
     };
     //获得消息事件
     socket.onmessage = function(msg) {
     console.log(msg.data);
     //发现消息进入    开始处理前端触发逻辑
     };
     //关闭事件
     socket.onclose = function() {
     console.log("Socket已关闭");
     };
     //发生了错误事件
     socket.onerror = function() {
     alert("Socket发生了错误");
     //此时可以尝试刷新页面
     }
    
    }
    

    请求页面与推送消息

    [http://127.0.0.1:18080/checkcenter/socket/2 第一次请求

    http://127.0.0.1:18080/checkcenter/socket/push/2?message=%E4%B8%80%E5%A4%A9](http://127.0.0.1:18080/checkcenter/socket/push/2?message=一天)

    对2窗口发送消息

    //页面请求
    @GetMapping("/socket/{cid}")
    public ModelAndView socket(@PathVariable String cid) {
     ModelAndView mav=new ModelAndView("/socket");
     mav.addObject("cid", cid);
     return mav;
    }
    ​
    /**
     * 发送消息 推送数据接口
     * @param cid
     * @param message
     * @return
     */
    @ResponseBody
    @RequestMapping("/socket/push/{cid}")
    public String pushToWeb(@PathVariable String cid,String message) {
     try {
     WebSocketServer.sendInfo(message,cid);
     } catch (IOException e) {
     e.printStackTrace();
     return "error" + cid+"#"+e.getMessage();
     }
     return "success" + cid;
    }
    

    相关socket服务方法

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import javax.websocket.OnClose;
    import javax.websocket.OnError;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    ​
    /**
     * @description: WebSocketServer消息服务
     * @author: Shenshuaihu
     * @version: 1.0
     * @data: 2019-03-18 17:02
     */
    ​
    @ServerEndpoint("/websocket/{sid}")
    @Component
    @Slf4j
    public class WebSocketServer {
    ​
     //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     private static int onlineCount = 0;
     //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
     private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
    ​
     //与某个客户端的连接会话,需要通过它来给客户端发送数据
     private Session session;
    ​
     //接收sid
     private String sid="";
     /**
     * 连接建立成功调用的方法*/
     @OnOpen
     public void onOpen(Session session,@PathParam("sid") String sid) {
     this.session = session;
     webSocketSet.add(this);     //加入set中
     addOnlineCount();           //在线数加1
     log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());
     this.sid=sid;
     try {
     sendMessage("连接成功");
     } catch (IOException e) {
     log.error("websocket IO异常");
     }
     }
    ​
     /**
     * 连接关闭调用的方法
     */
     @OnClose
     public void onClose() {
     webSocketSet.remove(this);  //从set中删除
     subOnlineCount();           //在线数减1
     log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
     }
    ​
     /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     *
     **/
     @OnMessage
     public void onMessage(String message, Session session) {
     log.info("收到来自窗口"+sid+"的信息:"+message);
     //群发消息
     for (WebSocketServer item : webSocketSet) {
     try {
     item.sendMessage(message);
     } catch (IOException e) {
     e.printStackTrace();
     }
     }
     }
    ​
     /**
     *
     * @param session
     * @param error
     */
     @OnError
     public void onError(Session session, Throwable error) {
     log.error("发生错误");
     error.printStackTrace();
     }
     /**
     * 实现服务器主动推送
     */
     public void sendMessage(String message) throws IOException {
     this.session.getBasicRemote().sendText(message);
     }
    ​
    ​
     /**
     * 群发自定义消息
     * */
     public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
     log.info("推送消息到窗口"+sid+",推送内容:"+message);
     for (WebSocketServer item : webSocketSet) {
     try {
     //这里可以设定只推送给这个sid的,为null则全部推送
     if(sid == null) {
     item.sendMessage(message);
     } else if(item.sid.equals(sid)){
     item.sendMessage(message);
     }
     } catch (IOException e) {
     continue;
     }
     }
     }
    ​
     public static synchronized int getOnlineCount() {
     return onlineCount;
     }
    ​
     public static synchronized void addOnlineCount() {
     WebSocketServer.onlineCount++;
     }
    ​
     public static synchronized void subOnlineCount() {
     WebSocketServer.onlineCount--;
     }
    }
    

    以下是我在一个项目上应用到的,是调用一个用时比较久的API,把实时消息返回给用户。

    function toText(id) {
    ​
     $("#message").attr("disabled", true);
    ​
     $.ajax({
     // url : BaseUrl+'/to/text',
     url : '/to/text',
     type : "POST",
     data : {"id" : id ,"sid" : sid } ,
     success : function(data) {
     if(data.success) {
     layer.close(messageWin);
     $('#message').addClass("hide"); //取消继续隐藏
     // 刷新数据
     $(".layui-laypage-btn")[0].click();
    ​
     } else {
     layer.close(messageWin);
     //eg1
     layer.confirm(data.data, {icon: 3, title:'失败提示'}, function(index){
     layer.close(index);
     });
     $('#message').addClass("hide"); //取消继续隐藏
     }
     $("#message").attr("disabled", false);
    ​
     },
     error : function() {
    ​
     }
     });  // ajax结束
    ​
    }
    ​
    function f1() {
    ​
     $('#message').removeClass("hide");
    ​
     messageWin =  layer.open({
     type : 1,
     shade : 0.4,
     title : '正在执行',
     shadeClose: true, //点击遮罩关闭层
     area : [ '300px', '250px' ], //显示空间
     content : $('#message'), //捕获的元素
     cancel : function(index) {
     layer.close(messageWin);
     $('#message').addClass("hide"); //取消继续隐藏
     }
     });
    ​
     // 改变状态
    ​
    }
    ​
    ​
    ​
    var socket;
    if(typeof(WebSocket) == "undefined") {
     console.log("您的浏览器不支持WebSocket");
    }else{
     var url='ws://'+window.location.host+'/websocket/' + sid;
     console.log("您的浏览器支持WebSocket");
     socket = new WebSocket(url);
     //打开事件
     socket.onopen = function() {
     console.log("Socket 已打开");
     socket.send("这是来自客户端的消息" + location.href + new Date());
     };
     //获得消息事件
     socket.onmessage = function(msg) {
     console.log(msg.data);
     //发现消息进入    开始处理前端触发逻辑
     sendMessage(msg.data);
    ​
     };
     //关闭事件
     socket.onclose = function() {
     console.log("Socket已关闭");
     };
     //发生了错误事件
     socket.onerror = function() {
     alert("Socket发生了错误");
     }
    ​
    }
    ​
    function sendMessage(message) {
     $('#socket').html('转换中,请等待,请勿关闭窗口!!! ' + '\n' + message);
     if (message === "保存文件") {
     console.log("messageWin 已关闭");
     }
    }
    

    需要注意的是后端发送消息时要对于sid,免得推送错了。本章部分内容是整合过的文章,如有改善请告知。

    相关文章

      网友评论

        本文标题:WebSocket-服务器到客户端的请求

        本文链接:https://www.haomeiwen.com/subject/ktikzqtx.html