WebSocket - NIO非堵塞版本 v2

多線程方式發生數據到前端(防止堵塞) 

package com.chuangqi.core.socket;

import com.chuangqi.jna.DllMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 流程:
 * 1. 前端先和後臺建立連接,url:/websocket/{當前瀏覽器用戶id};
 * 2. 前端調用send()方法發送數據到後臺,方法(內容參數,當前瀏覽器用戶uuid),後臺進行輪詢調用態勢顯示;
 * 注:通過“當前瀏覽器用戶id”進行區分推送消息到那個客戶端
 *
 * @author qizhentao
 * @version V1.0
 */
@Controller
@Component
//訪問服務端的url地址
@ServerEndpoint(value = "/websocket/{id}")
public class WebSocketServer {
    /**
     * 在線數
     */
    private static int onlineCount = 0;

    private static ConcurrentHashMap<String, WebSocketServer> webSocketSet = new ConcurrentHashMap<>();

    //與某個客戶端的連接會話,需要通過它來給客戶端發送數據
    private Session session;
    private String id = "";
    private boolean isRun = true;// 判斷是否結束死循環-結束數據傳輸
    private static Logger log = LogManager.getLogger(WebSocketServer.class);

    /**
     * 連接建立成功調用的方法
     */
    @OnOpen
    public void onOpen(@PathParam(value = "id") String id, Session session) {
        this.session = session;
        this.id = id;//接收到發送消息的人員編號
        webSocketSet.put(id, this);     //加入set中
        addOnlineCount();           //在線數加1
        log.info("用戶" + id + "加入!當前在線人數爲" + getOnlineCount());
        try {
            // 相應客戶端
            sendMessage("連接成功");
        } catch (IOException e) {
            log.error("websocket IO異常");
        }
    }

    /**
     * 連接關閉調用的方法,前端調用onClone方法進行關閉
     * http://tieba.baidu.com/p/6173318895?traceid=
     */
    @OnClose
    public void onClose() {
        log.info("執行socket的onClose(),關閉id爲{}的用戶", id);
        // 關閉當前用戶連接
        webSocketSet.remove(this);  //從set中刪除當前用戶
        subOnlineCount();           //在線數減1
        isRun = false;// fasle=關閉socket連接,停止while循環
        log.info("有一連接關閉!當前在線人數爲" + getOnlineCount());
    }

    /**
     * 收到客戶端消息後調用的方法
     * - 態勢顯示服務初始化後前端調用send()方法告訴後臺可以輪詢發送數據,格式爲:數據|建立socket連接時傳入的id
     *
     * @param message 客戶端發送過來的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("來自客戶端的消息:" + message);
        //可以自己約定字符串內容,比如   “進行輪詢態勢|0“ 表示信息羣發,   “進行輪詢態勢|x“ 表示信息發給id爲X的用戶
        String sendMessage = message.split("[|]")[0];
        String sendUserId = message.split("[|]")[1];
        try {
            if (sendUserId.equals("0"))
                sendtoAll(sendMessage);
            else
                sendtoUser(sendMessage, sendUserId);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("發生錯誤");
        error.printStackTrace();
    }

    /**
     * 響應客戶端消息
     *
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 發送信息給指定ID用戶,如果用戶不在線則返回不在線信息給自己
     *
     * @param message
     * @param sendUserId
     * @throws IOException
     */
    public void sendtoUser(String message, String sendUserId) throws IOException {
        if (webSocketSet.get(sendUserId) != null) {
            ExecutorService ex = Executors.newCachedThreadPool();
            ex.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        while (isRun) {
                            // 調用動態庫,接收數據(實時數據發送給前端!!!)
                            String data = DllMap.instance.GetInteractiveData(false);

                            if(!id.equals(sendUserId)){
                                webSocketSet.get(sendUserId).sendMessage(data);
                            }else{
                                webSocketSet.get(sendUserId).sendMessage(data);
                            }
                            try {Thread.sleep(800);} catch (InterruptedException e) {e.printStackTrace();}
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

        } else {
            //如果用戶不在線則返回不在線信息給自己
            //sendtoUser("當前用戶不在線",id);
        }

    }

    /**
     * 發送信息給所有人
     *
     * @param message
     * @throws IOException
     */
    public void sendtoAll(String message) throws IOException {
        for (String key : webSocketSet.keySet()) {
            try {
                webSocketSet.get(key).sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}

 

發佈了99 篇原創文章 · 獲贊 15 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章