คำนำ
HTML5 WebSocket ใช้การสื่อสารสองทางระหว่างเซิร์ฟเวอร์และเบราว์เซอร์ การสื่อสารแบบสองทางทำให้การพัฒนาข้อความเซิร์ฟเวอร์แบบพุชง่ายขึ้น สิ่งที่พบบ่อยที่สุดคือการสื่อสารทันทีและแอปพลิเคชันที่ต้องการข้อมูลคุณภาพสูงแบบเรียลไทม์ ข้อความเซิร์ฟเวอร์ก่อนหน้านี้ส่วนใหญ่ผลักดันเทคโนโลยี "การสำรวจ" และ "การเชื่อมต่อยาว" ซึ่งทั้งสองอย่างนี้จะต้องมีค่าใช้จ่ายจำนวนมากบนเซิร์ฟเวอร์และประสิทธิภาพแบบเรียลไทม์ไม่สูงเป็นพิเศษ เทคโนโลยี WebSocket จะมีค่าใช้จ่ายเล็ก ๆ น้อย ๆ และสูงเป็นเวลาจริงโดยเฉพาะ เริ่มต้นด้วยการอธิบายวิธีใช้เทคโนโลยี WebSocket เพื่อพัฒนาห้องแชท ในตัวอย่างนี้ใช้เซิร์ฟเวอร์ Tomcat7 แต่ละเซิร์ฟเวอร์มีการใช้งาน WebSocket ที่แตกต่างกันดังนั้นอินสแตนซ์นี้สามารถเรียกใช้ในเซิร์ฟเวอร์ Tomcat เท่านั้น อย่างไรก็ตาม Spring ได้เปิดตัว WebSocket API ซึ่งเข้ากันได้กับการใช้งานของแต่ละเซิร์ฟเวอร์ คุณสามารถปรึกษาข้อมูลที่เกี่ยวข้องเพื่อทำความเข้าใจ ฉันจะไม่แนะนำที่นี่ ภาพต่อไปนี้คือการแสดงผลของห้องสนทนา:
ในตัวอย่างนี้มีการใช้ข้อความแบบเรียลไทม์และการแจ้งเตือนออนไลน์และออฟไลน์ของผู้ใช้แชทจะถูกนำไปใช้เช่นกัน มาเริ่มอธิบายรายละเอียดเกี่ยวกับวิธีการใช้งาน
การประมวลผลแบ็กเอนด์
Tomcat ส่วนใหญ่ใช้ WebSocket โดยอาศัย org.apache.catalina.websocket.messageinbound คลาส คลาสนี้อยู่ใน {tomcat_home} /lib/catalina.jar ดังนั้นเมื่อคุณพัฒนาคุณต้องแนะนำ catalina.jar และ tomcat-coyote.jar รหัสต่อไปนี้สัมผัสกับที่อยู่เซิร์ฟเล็ตของไคลเอนต์:
แพ็คเกจ com.ibcio; นำเข้า Javax.servlet.annotation.webservlet; นำเข้า javax.servlet.http.httpservletrequest; นำเข้า org.apache.catalina.websocket.streaminbound; @webservlet (urlpatterns = {"/message"}) // หากคุณต้องการรับคำขอจาก WS ของเบราว์เซอร์: // โปรโตคอลคุณต้องใช้ WebSocketServlet คลาสสาธารณะ WebSocketMessageservlet ขยาย org.apache.catalina.websocket.websockets สาธารณะคงที่ int online_user_count = 1; Public String GetUser (คำขอ httpservletRequest) {return (string) request.getSession (). getAttribute ("ผู้ใช้"); } // ไม่เหมือน servlets ทั่วไป, createWebsocketInbound จำเป็นต้องใช้งานและวัตถุการเชื่อมต่อ WebSocket ที่กำหนดเองได้รับการเริ่มต้นที่นี่ @Override ป้องกัน StreaminBound CreateWebsocketInbound (สตริง subprotocol, httpservlet - servlet นี้ค่อนข้างแตกต่างจาก servlets ธรรมดา มันสืบทอดคลาส WebSocketServlet และจำเป็นต้องแทนที่วิธี CreateWebSocketInbound แอตทริบิวต์ผู้ใช้ในเซสชันในคลาสนี้ถูกตั้งค่าเมื่อผู้ใช้ป้อน index.jsp และบันทึกชื่อเล่นของผู้ใช้ปัจจุบัน ต่อไปนี้เป็นรหัสของคลาส WebSocketMessageInbound ที่ใช้งานด้วยตัวเอง:
แพ็คเกจ com.ibcio; นำเข้า java.io.ioException; นำเข้า java.nio.bytebuffer; นำเข้า java.nio.charbuffer; นำเข้า net.sf.json.jsonobject; นำเข้า org.apache.catalina.websocket.messageinbound; นำเข้า org.apache.catalina.websocket.wsoutbound; คลาสสาธารณะ WebSocketMessageInbound ขยาย MessageInbound {// ชื่อผู้ใช้ของการเชื่อมต่อปัจจุบันคือผู้ใช้สตริงสุดท้ายส่วนตัว Public WebSocketMessageInbound (ผู้ใช้สตริง) {this.user = ผู้ใช้; } สตริงสาธารณะ getUser () {return this.user; } // เหตุการณ์ทริกเกอร์โดยการสร้างการเชื่อมต่อ @Override void onopen (wsoutbound ขาออก) {// ทริกเกอร์เหตุการณ์การเชื่อมต่อและเพิ่มการเชื่อมต่อในผลการเชื่อมต่อพูล jsonObject = new jsonObject (); result.element ("type", "user_join"); result.element ("ผู้ใช้", this.user); // กดข้อความว่าผู้ใช้ปัจจุบันออนไลน์ไปยังผู้ใช้ออนไลน์ทั้งหมด WebSocketMessageInBoundPool.SendMessage (result.toString ()); ผลลัพธ์ = new JsonObject (); result.element ("type", "get_online_user"); result.element ("list", websocketMessageInboundPool.getOnlineUser ()); // เพิ่มวัตถุการเชื่อมต่อปัจจุบันลงในพูลการเชื่อมต่อ WebSocketMessageInboundPool.addMessageInbound (นี่); // ส่งรายชื่อผู้ใช้ออนไลน์ปัจจุบันไปยังการเชื่อมต่อปัจจุบัน WebSocketMessageInBoundPool.SendMessagetouser (this.user, result.toString ()); } @Override void onClose (สถานะ int) {// ทริกเกอร์เหตุการณ์การปิดและลบการเชื่อมต่อจากการเชื่อมต่อพูล WebSocketMessageInboundPool.removeMessageInbound (นี่); jsonObject result = new JSonObject (); result.element ("type", "user_leave"); result.element ("ผู้ใช้", this.user); // ส่งข้อความไปยังผู้ใช้ออนไลน์ว่าผู้ใช้ปัจจุบันออกจาก WebSocketMessageInBoundPool.SendMessage (result.toString ()); } @Override void protected onbinaryMessage (ข้อความ bytebuffer) โยน ioexception {โยน unsupportedoperationException ใหม่ ("ข้อความไบนารีไม่รองรับ"); } // เหตุการณ์จะถูกทริกเกอร์เมื่อไคลเอนต์ส่งข้อความไปยังเซิร์ฟเวอร์ @Override ป้องกันโมฆะ ontextMessage (ข้อความ Charbuffer) พ่น IOException {// ส่งข้อความไปยังผู้ใช้ออนไลน์ทั้งหมด webSocketMessageInboundPool.SENDMESSAGE - รหัสส่วนใหญ่ใช้วิธีการเปิดใช้งาน, onclose และ ontextmessage ซึ่งจัดการกับผู้ใช้ออนไลน์ออฟไลน์และส่งข้อความตามลำดับ มี WebSocketMessageInboundPool Class Class ในชั้นเรียนนี้ คลาสนี้ใช้เพื่อจัดการการเชื่อมต่อของผู้ใช้ออนไลน์ในปัจจุบัน ต่อไปนี้เป็นรหัสของคลาสนี้:
แพ็คเกจ com.ibcio; นำเข้า java.io.ioException; นำเข้า java.nio.charbuffer; นำเข้า java.util.hashmap; นำเข้า java.util.map; นำเข้า java.util.set; คลาสสาธารณะ WebSocketMessageInBoundPool {// บันทึกแผนที่คอนเทนเนอร์สำหรับการเชื่อมต่อแผนที่สุดท้ายคงที่ <String, WebSocketMessageInbound> การเชื่อมต่อ = new HashMap <String, WebSocketMessageInbound> (); // เพิ่มการเชื่อมต่อกับพูลการเชื่อมต่อโมฆะสาธารณะคงที่ addMessageInbound (WebSocketMessageInbound ขาเข้า) {// เพิ่ม System.out.out.println ("ผู้ใช้:" inbound.getUser () + "เข้าร่วม .. "); connections.put (inbound.getUser (), ขาเข้า); } // รับ Set Static Public Static ทั้งหมด <String> getOnlineUser () {return connections.keyset (); } โมฆะคงที่สาธารณะ removeMessageInbound (websocketMessageInbound ขาเข้า) {// ลบการเชื่อมต่อ System.out.println ("ผู้ใช้:" + inbound.getUser () + "ออก .. "); connections.remove (inbound.getuser ()); } โมฆะคงที่สาธารณะ sendMessAgetouser (ผู้ใช้สตริง, ข้อความสตริง) {ลอง {// ส่งข้อมูลไปยังผู้ใช้เฉพาะ System.out.println ("ส่งข้อความถึงผู้ใช้:" + ผู้ใช้ + "เนื้อหาข้อความ:" + ข้อความ); WebSocketMessageInbound inbound = connections.get (ผู้ใช้); if (inbound! = null) {inbound.getWsoutbound (). writeTextMessage (charbuffer.wrap (ข้อความ)); }} catch (ioexception e) {e.printstacktrace (); }} // ส่งข้อความไปยังผู้ใช้ทั้งหมดโมฆะสาธารณะคงที่ sendMessage (ข้อความสตริง) {ลอง {set <String> keyset = connections.keyset (); สำหรับ (คีย์สตริง: คีย์เซ็ต) {WebSocketMessageInbound inbound = connections.get (คีย์); if (inbound! = null) {system.out.println ("ส่งข้อความไปยังผู้ใช้:" + คีย์ + "เนื้อหาข้อความ:" + ข้อความ); inbound.getWsoutbound (). writetextmessage (charbuffer.wrap (ข้อความ)); }}} catch (ioexception e) {e.printstacktrace (); - หน้าจอแผนกต้อนรับส่วนหน้า
รหัสด้านบนคือรหัสของแบ็กเอนด์ห้องแชทซึ่งส่วนใหญ่ประกอบด้วยวัตถุ 3 ชิ้น, servlet, วัตถุเชื่อมต่อและกลุ่มการเชื่อมต่อ ต่อไปนี้เป็นรหัสของแผนกต้อนรับ รหัสของแผนกต้อนรับส่วนใหญ่ใช้การเชื่อมต่อกับเซิร์ฟเวอร์และแสดงรายการผู้ใช้และรายการข้อมูล การแสดงผลของแผนกต้อนรับใช้เฟรมเวิร์ก EXT นักเรียนที่ไม่คุ้นเคยกับ Ext สามารถมีความเข้าใจเบื้องต้นเกี่ยวกับ Ext ต่อไปนี้เป็นรหัสของ index.jsp:
<%@ page language = "java" pageencoding = "utf-8" import = "com.ibcio.webSocketMessageServlet"%> <%string user = (string) เซสชัน. getAttribute ("ผู้ใช้"); if (user == null) {// สร้างชื่อเล่นสำหรับผู้ใช้ผู้ใช้ = "แขก" + websocketMessageServlet.online_user_count; WebSocketMessageservlet.online_user_count ++; session.setAttribute ("ผู้ใช้", ผู้ใช้); } pageContext.setAttribute ("ผู้ใช้", ผู้ใช้); %> <html> <head> <title> ห้องแชท WebSocket </title> <!-แนะนำไฟล์ css-> <link rel = "stylesheet" type = "text/css" href = "ext4/resources/css/ext-all.css"> <link rel = "stylesheet" rel = "stylesheet" type = "text/css" href = "css/websocket.css"/> <!- แพ็คเกจการพัฒนา JS ของ Input Ext และ WebScoket ที่ใช้งานของมันเอง -> <script type = "text/javascript" src = "ext4/ext-all-debug.js"> </script> <script type = "text/javaScript" src = "websocket.js"> </script> <script type = "text/javascript"> var user = "$ {ผู้ใช้}"; </script> </head> <body> <h1> ห้องแชท WebSocket </h1> <p> API ที่จัดทำโดยมาตรฐาน HTML5 นั้นรวมกับเฟรมเวิร์กไคลเอนต์ที่อุดมไปด้วย Ext เพื่อใช้ห้องแชท การสื่อสารข้อมูลที่สมบูรณ์ซึ่งแตกต่างจากเทคโนโลยีเช่นการสำรวจและการเชื่อมต่อที่ยาวนานและบันทึกทรัพยากรเซิร์ฟเวอร์ </li> <li> รวมกับ ext สำหรับการแสดงหน้า </li> <li> ผู้ใช้ออนไลน์และการแจ้งเตือนออฟไลน์ </li></ul> <div id = "websocket_button" การแสดงหน้าของหน้าส่วนใหญ่จะถูกควบคุมใน websocket.js ต่อไปนี้เป็นรหัสของ websocket.jsd:
// ใช้เพื่อแสดงข้อมูลการแชทของผู้ใช้ ext.define ('MessageContainer', {ขยาย: 'ext.view.view', trackover: true, multiselect: false, itemcls: 'l-im-message', itemlector: 'div.l-im-message' {Overflow: 'Auto', BackgroundColor: '#FFF'}, TPL: ['<div> อย่าไว้วางใจการโอนเงินการชนะหรือโทรศัพท์ที่ไม่คุ้นเคยระหว่างการสนทนา '<div> {เนื้อหา} </div>', '</div>', '</tpl>'], ข้อความ: [], initcomponent: function () {var me = this.messageModel = ext.define ('leetop.im.messagemodel' 'Source']}); me.store = ext.create ('ext.data.store', {รุ่น: 'leetop.im.messagemodel', ข้อมูล: me.messages}); ข้อความ ['timestamp'] = ext.date.format (วันที่ใหม่ (ข้อความ ['timestamp']), 'h: i: s'); if (message.from == ผู้ใช้) {message.source = 'self'; } else {message.source = 'remote'; } me.store.add (ข้อความ); ถ้า (me.el.dom) {me.el.dom.scrolltop = me.el.dom.scrollheight; - รหัสนี้ใช้คอนเทนเนอร์ที่แสดงข้อความเป็นหลัก ต่อไปนี้เป็นรหัสที่เริ่มดำเนินการหลังจากโหลดหน้าเว็บ:
ext.onready (function () {// สร้างกล่องอินพุตผู้ใช้ var input = ext.create ('ext.form.field.htmleditor', {ภูมิภาค: 'ใต้', ความสูง: 120, enableFont: false, eNableSourceedit: false {ถ้า e.ctrlkey === true && e.keycode == 13) {E.PreventDefault (); ext.create ('ext.panel.panel', {region: 'center', เลย์เอาต์: 'border', รายการ: [อินพุต, เอาท์พุท], ปุ่ม: [{text: 'ส่ง', handler: send}]}); WebSocket (encodeuri ('ws: // localhost: 8080/websocket/message'); } webSocket.onclose = function () {// การเชื่อมต่อตัดการเชื่อมต่อ win.settitle (ชื่อ + '(ยกเลิกการเชื่อมต่อ)'); } // การรับข้อความ websocket.onMessage = ฟังก์ชั่น (ข้อความ) {var message = json.parse (message.data); // รับข้อความที่ส่งโดยผู้ใช้ถ้า (message.type == 'ข้อความ') {output.receive (ข้อความ); } อื่นถ้า (message.type == 'get_online_user') {// รับรายการผู้ใช้ออนไลน์ var root = onlineUser.getRootNode (); ext.each (message.list, ฟังก์ชั่น (ผู้ใช้) {var node = root.createnode ({id: ผู้ใช้, ข้อความ: ผู้ใช้, ไอคอน: 'ผู้ใช้', leaf: true}); root.appendchild (node);}); } อื่นถ้า (message.type == 'user_join') {// ผู้ใช้ไปออนไลน์ var root = onlineUser.getRootNode (); var user = message.user; var node = root.createnode ({id: ผู้ใช้, ข้อความ: ผู้ใช้, iconcls: 'ผู้ใช้', leaf: true}); root.appendchild (โหนด); } อื่นถ้า (message.type == 'user_leave') {// ผู้ใช้ไปออฟไลน์ var root = onlineUser.getRootNode (); var user = message.user; var node = root.findChild ('id', ผู้ใช้); root.removeChild (โหนด); - // ทรีผู้ใช้ออนไลน์ var onlineUser = ext.create ('ext.tree.panel', {title: 'ออนไลน์', rootvisible: false, ภูมิภาค: 'ตะวันออก', ความกว้าง: 150, บรรทัด: false, usearrows: true, autoscroll: จริง 'ผู้ใช้ออนไลน์', ขยาย: จริง, เด็ก: []}})}); var title = 'ยินดีต้อนรับ:' + ผู้ใช้; // แสดงหน้าต่าง var win = ext.create ('ext.window.window', {ชื่อเรื่อง: ชื่อเรื่อง + '(ไม่เชื่อมต่อ)', เลย์เอาต์: 'ชายแดน', ไอคอน: ผู้ฟัง: {render: function () {initwebsocket ();}}}); win.show (); // ส่งฟังก์ชันข้อความส่ง () {var message = {}; if (webSocket! = null) {ถ้า (input.getValue ()) {ext.apply (ข้อความ, {จาก: ผู้ใช้, เนื้อหา: input.getValue (), timestamp: วันที่ใหม่ (). getTime (), พิมพ์: 'ข้อความ'}); websocket.send (json.stringify (ข้อความ)); //output.receive(message); input.setValue (''); }} else {ext.msg.alert ('เคล็ดลับ', 'คุณถูกตัดการเชื่อมต่อและไม่สามารถส่งข้อความได้!'); -รหัสด้านบนเป็นรหัสที่เชื่อมต่อกับเซิร์ฟเวอร์โดยอัตโนมัติหลังจากโหลดหน้าเว็บและสร้างอินเทอร์เฟซที่แสดง
สังเกต
สองจุดที่ควรทราบ: หลังจากการปรับใช้เสร็จสมบูรณ์ catalina.jar และ tomcat-coyot.jar ในไดเรกทอรี LIB ในไดเรกทอรีแอปพลิเคชัน Tomcat จะต้องถูกลบ ตัวอย่างเช่นไดเรกทอรี LIB ของโครงการคือ D:/WorksPACE/WORKSPACE/WEBSOCKET/WEBROOT/WEB-INF/LIB และไดเรกทอรี LIB แอปพลิเคชันที่ปรับใช้คือ D: /tools/Apache-tomcat-7.0.32/webapps/websocket/web-inf/lib เพียงลบไดเรกทอรี LIB ของไดเรกทอรีการปรับใช้และเชื่อมต่อสองขวด มิฉะนั้นข้อผิดพลาดอาจไม่ได้เริ่มต้น จดจำ.
หากการเชื่อมต่อยังไม่สามารถทำได้โปรดดาวน์โหลด Tomcat ล่าสุด ลืมไปแล้วว่า TomCatCreateWebsocketInbound เวอร์ชันนั้นไม่มีพารามิเตอร์คำขอ รหัสปัจจุบันมีพารามิเตอร์นี้ รุ่น 7.0.3xx ทั้งหมดมาพร้อมกับพารามิเตอร์นี้จำไว้
สรุป
การใช้ WebSocket เพื่อพัฒนา Server Push นั้นสะดวกมาก นี่คือแอปพลิเคชั่นที่ง่าย ในความเป็นจริงมันยังสามารถรวม WEBRTC เพื่อรับรู้วิดีโอแชทและแชทด้วยเสียง
ดาวน์โหลดตัวอย่าง
ดาวน์โหลดที่อยู่: สาธิต
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น