Java后端WebSocket的Tomcat實現

?

原文:https://www.cnblogs.com/xdp-gacl/p/5193279.html

一.WebSocket簡單介紹

  隨著互聯網的發展,傳統的HTTP協議已經很難滿足Web應用日益復雜的需求了。近年來,隨著HTML5的誕生,WebSocket協議被提出,它實現了瀏覽器與服務器的全雙工通信,擴展了瀏覽器與服務端的通信功能,使服務端也能主動向客戶端發送數據。

  我們知道,傳統的HTTP協議是無狀態的,每次請求(request)都要由客戶端(如 瀏覽器)主動發起,服務端進行處理后返回response結果,而服務端很難主動向客戶端發送數據;這種客戶端是主動方,服務端是被動方的傳統Web模式 對于信息變化不頻繁的Web應用來說造成的麻煩較小,而對于涉及實時信息的Web應用卻帶來了很大的不便,如帶有即時通信、實時數據、訂閱推送等功能的應 用。在WebSocket規范提出之前,開發人員若要實現這些實時性較強的功能,經常會使用折衷的解決方法:輪詢(polling)Comet技術。其實后者本質上也是一種輪詢,只不過有所改進。

  輪詢是最原始的實現實時Web應用的解決方案。輪詢技術要求客戶端以設定的時間間隔周期性地向服務端發送請求,頻繁地查詢是否有新的數據改動。明顯地,這種方法會導致過多不必要的請求,浪費流量和服務器資源。

  Comet技術又可以分為長輪詢流技術長輪詢改進了上述的輪詢技術,減小了無用的請求。它會為某些數據設定過期時間,當數據過期后才會向服務端發送請求;這種機制適合數據的改動不是特別頻繁的情況。流技術通常是指客戶端使用一個隱藏的窗口與服務端建立一個HTTP長連接,服務端會不斷更新連接狀態以保持HTTP長連接存活;這樣的話,服務端就可以通過這條長連接主動將數據發送給客戶端;流技術在大并發環境下,可能會考驗到服務端的性能。

  這兩種技術都是基于請求-應答模式,都不算是真正意義上的實時技術;它們的每一次請求、應答,都浪費了一定流量在相同的頭部信息上,并且開發復雜度也較大。

  伴隨著HTML5推出的WebSocket,真正實現了Web的實時通信,使B/S模式具備了C/S模式的實時通信能力。WebSocket的工作流程是這 樣的:瀏覽器通過JavaScript向服務端發出建立WebSocket連接的請求,在WebSocket連接建立成功后,客戶端和服務端就可以通過 TCP連接傳輸數據。因為WebSocket連接本質上是TCP連接,不需要每次傳輸都帶上重復的頭部數據,所以它的數據傳輸量比輪詢和Comet技術小 了很多。本文不詳細地介紹WebSocket規范,主要介紹下WebSocket在Java Web中的實現。

  JavaEE 7中出了JSR-356:Java API for WebSocket規范。不少Web容器,如Tomcat,Nginx,Jetty等都支持WebSocket。Tomcat從7.0.27開始支持 WebSocket,從7.0.47開始支持JSR-356,下面的Demo代碼也是需要部署在Tomcat7.0.47以上的版本才能運行。

二.WebSocket示例

2.1.新建JavaWeb測試項目

  

  在pom.xml中添加Jar包依賴

復制代碼
1 <dependency>
2         <groupId>javax</groupId> 3 <artifactId>javaee-api</artifactId> 4 <version>7.0</version> 5 <scope>provided</scope> 6 </dependency>
復制代碼

  客戶端(Web主頁)代碼:

復制代碼
 1 <%@ page language="java" pageEncoding="UTF-8" %>  2 <!DOCTYPE html>  3 <html>  4 <head>  5 <title>Java后端WebSocket的Tomcat實現</title>  6 </head>  7 <body>  8 Welcome<br/><input id="text" type="text"/>  9 <button onclick="send()">發送消息</button> 10 <hr/> 11 <button onclick="closeWebSocket()">關閉WebSocket連接</button> 12 <hr/> 13 <div id="message"></div> 14 </body> 15 16 <script type="text/javascript"> 17 var websocket = null; 18 //判斷當前瀏覽器是否支持WebSocket 19 if ('WebSocket' in window) { 20  websocket = new WebSocket("ws://localhost:8080/項目名/websocket"); 21  } 22 else { 23  alert('當前瀏覽器 Not support websocket') 24  } 25 26 //連接發生錯誤的回調方法 27  websocket.onerror = function () { 28  setMessageInnerHTML("WebSocket連接發生錯誤"); 29  }; 30 31 //連接成功建立的回調方法 32  websocket.onopen = function () { 33  setMessageInnerHTML("WebSocket連接成功"); 34  } 35 36 //接收到消息的回調方法 37  websocket.onmessage = function (event) { 38  setMessageInnerHTML(event.data); 39  } 40 41 //連接關閉的回調方法 42  websocket.onclose = function () { 43  setMessageInnerHTML("WebSocket連接關閉"); 44  } 45 46 //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。 47 window.onbeforeunload = function () { 48 closeWebSocket(); 49 } 50 51 //將消息顯示在網頁上 52 function setMessageInnerHTML(innerHTML) { 53 document.getElementById('message').innerHTML += innerHTML + '<br/>'; 54 } 55 56 //關閉WebSocket連接 57 function closeWebSocket() { 58 websocket.close(); 59 } 60 61 //發送消息 62 function send() { 63 var message = document.getElementById('text').value; 64 websocket.send(message); 65 } 66 </script> 67 </html>
復制代碼

  Java Web后端代碼

復制代碼
 1 package me.gacl.websocket;
 2 
 3 import java.io.IOException;  4 import java.util.concurrent.CopyOnWriteArraySet;  5  6 import javax.websocket.*;  7 import javax.websocket.server.ServerEndpoint;  8  9 /** 10  * @ServerEndpoint 注解是一個類層次的注解,它的功能主要是將目前的類定義成一個websocket服務器端, 11  * 注解的值將被用于監聽用戶連接的終端訪問URL地址,客戶端可以通過這個URL來連接到WebSocket服務器端 12 */ 13 @ServerEndpoint("/websocket") 14 public class WebSocketTest { 15 //靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。 16 private static int onlineCount = 0; 17 18 //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通信的話,可以使用Map來存放,其中Key可以為用戶標識 19 private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>(); 20 21 //與某個客戶端的連接會話,需要通過它來給客戶端發送數據 22 private Session session; 23 24 /** 25  * 連接建立成功調用的方法 26  * @param session 可選的參數。session為與某個客戶端的連接會話,需要通過它來給客戶端發送數據 27 */ 28  @OnOpen 29 public void onOpen(Session session){ 30 this.session = session; 31 webSocketSet.add(this); //加入set中 32 addOnlineCount(); //在線數加1 33 System.out.println("有新連接加入!當前在線人數為" + getOnlineCount()); 34  } 35 36 /** 37  * 連接關閉調用的方法 38 */ 39  @OnClose 40 public void onClose(){ 41 webSocketSet.remove(this); //從set中刪除 42 subOnlineCount(); //在線數減1 43 System.out.println("有一連接關閉!當前在線人數為" + getOnlineCount()); 44  } 45 46 /** 47  * 收到客戶端消息后調用的方法 48  * @param message 客戶端發送過來的消息 49  * @param session 可選的參數 50 */ 51  @OnMessage 52 public void onMessage(String message, Session session) { 53 System.out.println("來自客戶端的消息:" + message); 54 //群發消息 55 for(WebSocketTest item: webSocketSet){ 56 try { 57  item.sendMessage(message); 58 } catch (IOException e) { 59  e.printStackTrace(); 60 continue; 61  } 62  } 63  } 64 65 /** 66  * 發生錯誤時調用 67  * @param session 68  * @param error 69 */ 70  @OnError 71 public void onError(Session session, Throwable error){ 72 System.out.println("發生錯誤"); 73  error.printStackTrace(); 74  } 75 76 /** 77  * 這個方法與上面幾個方法不一樣。沒有用注解,是根據自己需要添加的方法。 78  * @param message 79  * @throws IOException 80 */ 81 public void sendMessage(String message) throws IOException{ 82 this.session.getBasicRemote().sendText(message); 83 //this.session.getAsyncRemote().sendText(message); 84 } 85 86 public static synchronized int getOnlineCount() { 87 return onlineCount; 88 } 89 90 public static synchronized void addOnlineCount() { 91 WebSocketTest.onlineCount++; 92 } 93 94 public static synchronized void subOnlineCount() { 95 WebSocketTest.onlineCount--; 96 } 97 }
復制代碼

?1.2.運行效果

  同時打開Google瀏覽器和火狐瀏覽器進行多客戶端模擬測試,運行效果如下:

  

  該Demo在Jdk1.7+Tomcat7.0.65下環境測試過,示例項目代碼下載

  本篇博客的大部分內容轉載自http://blog.chenzuhuang.com/archive/28.html,然后在此基礎上進行完善,在此對作者表示感謝.

?

注意:如果按照上面一通操作后,還是頁面報錯 說鏈接不上 websocket 請參考文章:

1:WebSocket與Tomcat兼容問題

2:web項目引用tomcat中的jar

轉載于:https://www.cnblogs.com/libin6505/p/9707565.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/388405.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/388405.shtml
英文地址,請注明出處:http://en.pswp.cn/news/388405.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

加速業務交付,從 GKE 上使用 Kubernetes 和 Istio 開始

原文來源于&#xff1a;谷歌云技術博客 許多企業機構正在把全部或部分 IT 業務遷移到云端&#xff0c;幫助企業更好的運營。不過這樣的大規模遷移&#xff0c;在企業的實際操作中也有一定難度。不少企業保存在本地服務器的重要資源&#xff0c;并不支持直接遷移到云端。 另外&a…

knn 鄰居數量k的選取_選擇K個最近的鄰居

knn 鄰居數量k的選取Classification is more-or-less just a matter of figuring out to what available group something belongs.分類或多或少只是弄清楚某個事物所屬的可用組的問題。 Is Old Town Road a rap song or a country song?Old Town Road是說唱歌曲還是鄉村歌曲…

計算機網絡中 子網掩碼的算法,[網絡天地]子網掩碼快速算法(轉載)

看到一篇很好的資料&#xff0c;大家分享有很多人肯定對設定子網掩碼這個不熟悉&#xff0c;很頭疼&#xff0c;那么我現在就告訴大家一個很容易算子網掩碼的方法&#xff0c;幫助一下喜歡偷懶的人&#xff1a;)大家都應該知道2的0次方到10次方是多少把&#xff1f;也給大家說一…

EXTJS+JSP上傳文件帶進度條

需求來源是這樣的&#xff1a;上傳一個很大的excel文件到server&#xff0c; server會解析這個excel&#xff0c; 然后一條一條的插入到數據庫&#xff0c;整個過程要耗費很長時間&#xff0c;因此當用戶點擊上傳之后&#xff0c;需要顯示一個進度條&#xff0c;并且能夠根據后…

android Json詳解

Json:一種輕量級的數據交換格式&#xff0c;具有良好的可讀和便于快速編寫的特性。業內主流技術為其提供了完整的解決方案&#xff08;有點類似于正則表達式 &#xff0c;獲得了當今大部分語言的支持&#xff09;&#xff0c;從而可以在不同平臺間進行數據交換。JSON采用兼容性…

react實踐

React 最佳實踐一、 React 與 AJAXReact 只負責處理 View 這一層&#xff0c;它本身不涉及網絡請求 /AJAX: 第一&#xff0c;用什么技術從服務端獲取數據&#xff1b; 第二&#xff0c;獲取到的數據應該放在 react 組件的什么位置。 事實上是有很多的&#xff1a;fetch()、fetc…

什么樣的代碼是好代碼_什么是好代碼?

什么樣的代碼是好代碼編碼最佳實踐 (Coding Best-Practices) In the following section, I will introduce the topic at hand, giving you a sense of what this post will cover, and how each argument therein will be approached. Hopefully, this will help you decide w…

nginx比較apache

話說nginx在大壓力的環境中比apache的表現要好&#xff0c;于是下載了一個來折騰一下。 下載并編譯安裝&#xff0c;我的編譯過程有點特別&#xff1a; 1。去除調試信息&#xff0c;修改$nginx_setup_path/auto/cc/gcc這個文件&#xff0c;將 CFLAGS"$CFLAGS -g" …

計算機主板各模塊復位,電腦主板復位電路工作原理分析

電源、時鐘、復位是主板能正常工作的三大要素。主板在電源、時鐘都正常后&#xff0c;復位系統發出復位信號&#xff0c;主板各個部件在收到復位信號后&#xff0c;同步進入初始化狀態。如圖7-11所示為復位電路的工作原理圖&#xff0c;各個十板實現復位的電路不盡相同&#xf…

Docker制作dotnet core控制臺程序鏡像

(1)首先我們到某個目錄下&#xff0c;然后在此目錄下打開visual studio code. 2.編輯docker file文件如下: 3.使用dotnet new console創建控制臺程序; 4.使用docker build -t daniel/console:dev .來進行打包; 5.啟動并運行鏡像; 6.我們可以看到打包完的鏡像將近2G,因為我們使用…

【362】python 正則表達式

參考&#xff1a;正則表達式 - 廖雪峰 參考&#xff1a;Python3 正則表達式 - 菜鳥教程 參考&#xff1a;正則表達式 - 教程 re.match 嘗試從字符串的起始位置匹配一個模式&#xff0c;如果不是起始位置匹配成功的話&#xff0c;match()就返回none。 re.search 掃描整個字符串并…

在Python中使用Twitter Rest API批量搜索和下載推文

數據挖掘 &#xff0c; 編程 (Data Mining, Programming) Getting Twitter data獲取Twitter數據 Let’s use the Tweepy package in python instead of handling the Twitter API directly. The two things we will do with the package are, authorize ourselves to use the …

第一套數字電子計算機,計算機試題第一套

《計算機試題第一套》由會員分享&#xff0c;可在線閱讀&#xff0c;更多相關《計算機試題第一套(5頁珍藏版)》請在人人文庫網上搜索。1、計算機試題第一套1、計算機之所以能自動運算,就是由于采用了工作原理。A、布爾邏輯。B 儲存程序。C、數字電路。D,集成電路答案選B2、“長…

Windows7 + Nginx + Memcached + Tomcat 集群 session 共享

一&#xff0c;環境說明 操作系統是Windows7家庭版&#xff08;有點不專業哦&#xff0c;呵呵&#xff01;&#xff09;&#xff0c;JDK是1.6的版本&#xff0c; Tomcat是apache-tomcat-6.0.35-windows-x86&#xff0c;下載鏈接&#xff1a;http://tomcat.apache.org/ Nginx…

git 版本控制(一)

新建代碼庫repository 1、在當前目錄新建一個git代碼庫 git init git init projectname 2、下載一個項目&#xff0c;如果已經有了遠端的代碼&#xff0c;則可以使用clone下載 git clone url 增加/刪除/改名文件 1、添加指定文件到暫存區 git add filename 2、添加指定目錄到暫…

rollup學習小記

周末在家重構網關的Npm包&#xff0c;用到了rollup&#xff0c;記下筆記 rollup適合庫library的開發&#xff0c;而webpack適合應用程序的開發。 rollup也支持tree-shaking&#xff0c;自帶的功能。 package.json 也具有 module 字段&#xff0c;像 Rollup 和 webpack 2 這樣的…

大數據 vr csdn_VR中的數據可視化如何革命化科學

大數據 vr csdnAstronomy has become a big data discipline, and the ever growing databases in modern astronomy pose many new challenges for analysts. Scientists are more frequently turning to artificial intelligence and machine learning algorithms to analyze…

object-c 日志

printf和NSlog區別 NSLog會自動加上換行符&#xff0c;不需要自己添加換行符&#xff0c;NSLog會加上時間和進程信息&#xff0c;而printf僅將輸入的內容輸出不會添加任何額外的東西。兩者的輸入類型也是有區別的NSLog期待NSString*&#xff0c;而printf期待const char *。最本…

計算機真正管理的文件名是什么,計算機題,請大家多多幫忙,謝謝

4、在資源管理器中&#xff0c;若想顯示文件名、文件大小和文件類型&#xff0c;應采用什么顯示方式。( )A、小圖標顯示 B、列表顯示 C、詳細資料顯示 D、縮略圖顯示5、在EXCEL中&#xff0c;可以依據不同要求來提取和匯總數據&#xff0c;4、在資源管理器中&#xff0c;若想顯…

小a的排列

鏈接&#xff1a;https://ac.nowcoder.com/acm/contest/317/G來源&#xff1a;牛客網小a有一個長度為nn的排列。定義一段區間是"萌"的&#xff0c;當且僅當把區間中各個數排序后相鄰元素的差為11 現在他想知道包含數x,yx,y的長度最小的"萌"區間的左右端點 …