zoukankan      html  css  js  c++  java
  • WebSocket简单使用

    一.Socket的概要

    Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。Socket的英文原义是“孔”或“插座”,作为UNIX的进程通信机制。Socket可以实现应用程序间网络通信。

    Socket可以使用TCP/IP协议或UDP协议。

    TCP/IP协议

    TCP/IP协议是目前应用最为广泛的协议,是构成Internet国际互联网协议的最为基础的协议,由TCP和IP协议组成:
    TCP协议:面向连接的、可靠的、基于字节流的传输层通信协议,负责数据的可靠性传输的问题。

    IP协议:用于报文交换网络的一种面向数据的协议,主要负责给每台网络设备一个网络地址,保证数据传输到正确的目的地。

    UDP协议

    UDP特点:无连接、不可靠、基于报文的传输层协议,优点是发送后不用管,速度比TCP快。

    二.WebSocket的概要

    B/S架构的系统多使用HTTP协议,HTTP协议的特点:

    1 无状态协议
    2 用于通过 Internet 发送请求消息和响应消息
    3 使用端口接收和发送消息,默认为80端口
    底层通信还是使用Socket完成。

    HTTP协议决定了服务器与客户端之间的连接方式,无法直接实现消息推送(F5已坏),一些变相的解决办法:

    双向通信与消息推送

    轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。  优点:后端程序编写比较容易。  缺点:请求中有大半是无用,浪费带宽和服务器资源。  实例:适于小型应用。

    长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。  优点:在无消息的情况下不会频繁的请求,耗费资小。  缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 Comet异步的ashx, 实例:WebQQ、Hi网页版、Facebook IM。

    长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。  优点:消息即时到达,不发无用请求;管理起来也相对便。  缺点:服务器维护一个长连接会增加开销。  实例:Gmail聊天

    Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。  优点:实现真正的即时通信,而不是伪即时。  缺点:客户端必须安装Flash插件;非HTTP协议,无法自动穿越防火墙。  实例:网络互动游戏。

    Websocket:
    WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
    特点:
    事件驱动
    异步
    使用ws或者wss协议的客户端socket

    能够实现真正意义上的推送功能

    缺点:

    少部分浏览器不支持,浏览器支持的程度与方式有区别。

    WebSocket协议支持(在受控环境中运行不受信任的代码的)客户端与(选择加入该代码的通信的)远程主机之间进行全双工通信。用于此的安全模型是Web浏览器常用的基于原始的安全模式。 协议包括一个开放的握手以及随后的TCP层上的消息帧。 该技术的目标是为基于浏览器的、需要和服务器进行双向通信的(服务器不能依赖于打开多个HTTP连接(例如,使用XMLHttpRequest或<iframe>和长轮询))应用程序提供一种通信机制。
     

    三.WebSocket实例

    客户端(Web主页)代码:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>WebSocket前端</title>
      </head>
      <body>
        Welcome<br/><input id="text" type="text"/>
        <button onclick="send()">发送消息</button>
        <hr/>
        <button onclick="closeWebSocket">关闭WebSocket</button>
        <hr/>
        <div id="message"></div>
    
      </body>
      <script type="text/javascript">
        var websocket=null;
        //判断当前浏览器是否支持WebSocket
        if('WebSocket' in window){
            websocket=new WebSocket("ws://localhost:8080/websocket");
        }else{
            alert("当前浏览器 Not support websocket");
        }
    
        //连接发生错误的回调方法
        websocket.onerror=function(){
            setMessageInnerHTML("WebSocket连接发生错误");
        }
    
        //接收到消息的回调方法
        websocket.onmessage=function (event) {
            setMessageInnerHTML(event.data);
        }
    
        //连接关闭的回调方法
        websocket.onclose=function () {
            setMessageInnerHTML("WebSocket连接关闭");
        }
    
        //监听窗口关闭时间,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛出异常。
        window.onbeforeprint=function () {
            closeWebSocket();
        }
    
        //将消息显示在网页上
        function setMessageInnerHTML(innerHTML) {
            document.getElementById('message').innerHTML+=innerHTML+'<br/>';
        }
    
        //关闭WebSocket连接
        function closeWebSocket() {
            websocket.close();
        }
    
        //发送消息
        function send() {
            var message=document.getElementById('text').value;
            websocket.send(message);
        }
      </script>
    </html>

    后台代码:

    package com;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    
    @ServerEndpoint("/websocket")
    public class WebSocketTest {
        //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
        private static int onlineCount = 0;
    
        //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
        private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();
    
        //与某个客户端的连接会话,需要通过它来给客户端发送数据
        private Session session;
    
        /**
         * 连接建立成功调用的方法
         * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
         */
        @OnOpen
        public void onOpen(Session session){
            this.session = session;
            webSocketSet.add(this);     //加入set中
            addOnlineCount();           //在线数加1
            System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
        }
    
        /**
         * 连接关闭调用的方法
         */
        @OnClose
        public void onClose(){
            webSocketSet.remove(this);  //从set中删除
            subOnlineCount();           //在线数减1
            System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
        }
    
        /**
         * 收到客户端消息后调用的方法
         * @param message 客户端发送过来的消息
         * @param session 可选的参数
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            System.out.println("来自客户端的消息:" + message);
            //群发消息
            for(WebSocketTest item: webSocketSet){
                try {
                    item.sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    
        /**
         * 发生错误时调用
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error){
            System.out.println("发生错误");
            error.printStackTrace();
        }
    
        /**
         * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
         * @param message
         * @throws IOException
         */
        public void sendMessage(String message) throws IOException{
            this.session.getBasicRemote().sendText(message);
            //this.session.getAsyncRemote().sendText(message);
        }
    
        public static synchronized int getOnlineCount() {
            return onlineCount;
        }
    
        public static synchronized void addOnlineCount() {
            WebSocketTest.onlineCount++;
        }
    
        public static synchronized void subOnlineCount() {
            WebSocketTest.onlineCount--;
        }
    }
  • 相关阅读:
    android Context 持有导致的内存泄漏
    android PreferenceFragment
    android 修改 SwitchPreferenceCompat 高度,内边距,字体大小
    Android MPAndroidChart RadarChart (蜘蛛网图)
    Bugtags 测试平台(支持ios、android)
    BlockCanary 一个轻量的,非侵入式的性能监控组件(阿里)
    RecyclerView item 状态错乱
    RecyclerView android:layout_width="match_parent" 无效
    android-async-http cancelRequests
    Android MultiDex
  • 原文地址:https://www.cnblogs.com/wfhking/p/9445595.html
Copyright © 2011-2022 走看看