WebSocket

websocket

基于websocket小demo的理解


先講解一下什么叫網(wǎng)絡(luò)編程?

  • 網(wǎng)絡(luò)編程其實(shí)是對于信息的一個(gè)發(fā)送和接收
    • 發(fā)送端:將信息按照一定的協(xié)議組裝成一個(gè)數(shù)據(jù)包
    • 接受端:把收到的數(shù)據(jù)包進(jìn)行解析渠概,提取出其中的信息
  • Socket:兩個(gè)在網(wǎng)絡(luò)上的程序通過一個(gè)雙向的通信連接初厚,實(shí)現(xiàn)數(shù)據(jù)的交換况芒,這個(gè)鏈接的每個(gè)端口都可以稱為一個(gè)Socket
  • Socket的本質(zhì):Socket是一個(gè)編程接口(API)负乡,TCP/IP協(xié)議需要向開發(fā)者提供做網(wǎng)絡(luò)開發(fā)用的接口描孟,這就是Socket接口,它是對TCP/IP協(xié)議網(wǎng)絡(luò)通信的封裝晨炕。

下面是我自己寫的一個(gè)對于websocket的一個(gè)demo

第一步:導(dǎo)入對應(yīng)需要的jar包

<dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
  </dependency>

第二步:html頁面的代碼

<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<html>
<head>
<title>Java后端WebSocket的Tomcat實(shí)現(xiàn)</title>
      <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport' />
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
  Welcome<br/><input id="text" type="text"/>
  <button onclick="send()">發(fā)送消息</button>
  <hr/>
  <button onclick="closeWebSocket()">關(guān)閉WebSocket連接</button>
  <hr/>
  <div id="message"></div>
</body>
<script type="text/javascript">
    var websocket = null;
    //判斷當(dāng)前瀏覽器是否支持WebSocket
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://localhost:8080/websocket/websocket");
    }else {
        alert('當(dāng)前瀏覽器 Not support websocket')
    }
    //連接發(fā)生錯(cuò)誤的回調(diào)方法
    websocket.onerror = function () {
      setMessageInnerHTML("WebSocket連接發(fā)生錯(cuò)誤");
    };
    //連接成功建立的回調(diào)方法
    websocket.onopen = function () {
        setMessageInnerHTML("WebSocket連接成功");
    }
    //接收到消息的回調(diào)方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
    }
    //連接關(guān)閉的回調(diào)方法
    websocket.onclose = function () {
        setMessageInnerHTML("WebSocket連接關(guān)閉");
    }
    //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí)毫炉,主動(dòng)去關(guān)閉websocket連接瓮栗,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。
    window.onbeforeunload = function () {
        closeWebSocket();
    }
    //將消息顯示在網(wǎng)頁上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }
    //關(guān)閉WebSocket連接
    function closeWebSocket() {
        websocket.close();
    }
    //發(fā)送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

第三步:后臺(tái)接口

    package demo;
    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    /**
     * @ServerEndpoint 注解是一個(gè)類層次的注解费奸,它的功能主要是將目前的類定義成一個(gè)websocket服務(wù)器端,
     * 注解的值將被用于監(jiān)聽用戶連接的終端訪問URL地址,客戶端可以通過這個(gè)URL來連接到WebSocket服務(wù)器端
     */
    @ServerEndpoint("/websocket")
    public class WebSocketTest {
        //靜態(tài)變量弥激,用來記錄當(dāng)前在線連接數(shù)。應(yīng)該把它設(shè)計(jì)成線程安全的愿阐。
        private static int onlineCount = 0;
    
        //concurrent包的線程安全Set微服,用來存放每個(gè)客戶端對應(yīng)的MyWebSocket對象。若要實(shí)現(xiàn)服務(wù)端與單一客戶端通信的話缨历,可以使用Map來存放以蕴,其中Key可以為用戶標(biāo)識
        private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();
    
        //與某個(gè)客戶端的連接會(huì)話,需要通過它來給客戶端發(fā)送數(shù)據(jù)
        private Session session;
    
        /**
         * 連接建立成功調(diào)用的方法
         * @param session  可選的參數(shù)辛孵。session為與某個(gè)客戶端的連接會(huì)話丛肮,需要通過它來給客戶端發(fā)送數(shù)據(jù)
         */
        @OnOpen
        public void onOpen(Session session){
            this.session = session;
            webSocketSet.add(this);     //加入set中
            addOnlineCount();           //在線數(shù)加1
            System.out.println("有新連接加入!當(dāng)前在線人數(shù)為" + getOnlineCount());
        }
    
        /**
         * 連接關(guān)閉調(diào)用的方法
         */
        @OnClose
        public void onClose(){
            webSocketSet.remove(this);  //從set中刪除
            subOnlineCount();           //在線數(shù)減1
            System.out.println("有一連接關(guān)閉魄缚!當(dāng)前在線人數(shù)為" + getOnlineCount());
        }
    
        /**
         * 收到客戶端消息后調(diào)用的方法
         * @param message 客戶端發(fā)送過來的消息
         * @param session 可選的參數(shù)
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            System.out.println("來自客戶端的消息:" + message);
            //群發(fā)消息
            for(WebSocketTest item: webSocketSet){
                try {
                    item.sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    
        /**
         * 發(fā)生錯(cuò)誤時(shí)調(diào)用
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error){
            System.out.println("發(fā)生錯(cuò)誤");
            error.printStackTrace();
        }
    
        /**
         * 這個(gè)方法與上面幾個(gè)方法不一樣宝与。沒有用注解,是根據(jù)自己需要添加的方法冶匹。
         * @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--;
        }
    }

項(xiàng)目結(jié)構(gòu)圖如下

websocket.png

啟動(dòng)項(xiàng)目在不同瀏覽器中打開項(xiàng)目就可以實(shí)現(xiàn)簡單的socket的通訊了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末习劫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子徙硅,更是在濱河造成了極大的恐慌榜聂,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗓蘑,死亡現(xiàn)場離奇詭異须肆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)桩皿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門豌汇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泄隔,你說我怎么就攤上這事拒贱。” “怎么了佛嬉?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵逻澳,是天一觀的道長。 經(jīng)常有香客問我暖呕,道長斜做,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任湾揽,我火速辦了婚禮瓤逼,結(jié)果婚禮上笼吟,老公的妹妹穿的比我還像新娘。我一直安慰自己霸旗,他們只是感情好贷帮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著诱告,像睡著了一般撵枢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蔬啡,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天诲侮,我揣著相機(jī)與錄音,去河邊找鬼箱蟆。 笑死沟绪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的空猜。 我是一名探鬼主播绽慈,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼辈毯!你這毒婦竟也來了坝疼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谆沃,失蹤者是張志新(化名)和其女友劉穎钝凶,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唁影,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耕陷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了据沈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哟沫。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖锌介,靈堂內(nèi)的尸體忽然破棺而出嗜诀,到底是詐尸還是另有隱情,我是刑警寧澤孔祸,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布隆敢,位于F島的核電站,受9級特大地震影響崔慧,放射性物質(zhì)發(fā)生泄漏筑公。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一尊浪、第九天 我趴在偏房一處隱蔽的房頂上張望匣屡。 院中可真熱鬧,春花似錦拇涤、人聲如沸捣作。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽券躁。三九已至,卻和暖如春掉盅,著一層夾襖步出監(jiān)牢的瞬間也拜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工趾痘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留慢哈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓永票,卻偏偏與公主長得像卵贱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子侣集,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容