亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > HTML > 正文

html5利用websocket完成的推送功能

2024-08-26 00:18:15
字體:
來源:轉載
供稿:網友

利用websocket和java完成的消息推送功能,服務器用的是tomcat7.0,一些東西是自己琢磨的,也不知道恰不恰當,不恰當處,還請各位見諒,并指出。

程序簡單來說,就是客戶A可以發送消息給客戶B,但有很多可以擴展的地方,

比如

1.如果加入數據庫后,A發消息時客戶B未上線,服務端將會把消息存在數據庫中,等客戶B上線后,在將消息取出發送給客戶B

2.服務端也可發送消息到任意客戶端上。

程序的運行效果截圖如下(在chrome,搜狗,firefox下測試通過):代碼將在最后給出

首先我們打開一個瀏覽器,顯示輸入您的名字,這里我輸入soar

html5利用websocket完成的推送功能

html5利用websocket完成的推送功能

在打開第二個瀏覽器,這里我輸入bill

html5利用websocket完成的推送功能

html5利用websocket完成的推送功能

這是如果我發送hello bill i am soar給bill,點擊send

html5利用websocket完成的推送功能

在另一個瀏覽器上就可以看到

html5利用websocket完成的推送功能

Websocket

1.websocket是什么?

WebSocket是為解決客戶端與服務端實時通信而產生的技術。其本質是先通過HTTP/HTTPS協議進行握手后創建一個用于交換數據的TCP連接,

此后服務端與客戶端通過此TCP連接進行實時通信。

2.websocket的優點

以前我們實現推送技術,用的都是輪詢,在特點的時間間隔有瀏覽器自動發出請求,將服務器的消息主動的拉回來,在這種情況下,我們需要不斷的向服務器 發送請求,然而HTTP request 的header是非常長的,里面包含的數據可能只是一個很小的值,這樣會占用很多的帶寬和服務器資源。會占用大量的帶寬和服務器資源。

WebSocket API最偉大之處在于服務器和客戶端可以在給定的時間范圍內的任意時刻,相互推送信息。在建立連接之后,服務器可以主動傳送數據給客戶端。

此外,服務器與客戶端之間交換的標頭信息很小。

WebSocket并不限于以Ajax(或XHR)方式通信,因為Ajax技術需要客戶端發起請求,而WebSocket服務器和客戶端可以彼此相互推送信息;

關于ajax,comet,websocket的詳細介紹,和websocket報文的介紹,大家可以參看http://www.shaoqun.com/a/54588.aspx  網頁設計]Ajax、Comet與Websocket,

我如果以后有時間,也會寫出來的

3.如何使用websocket

客戶端

在支持WebSocket的瀏覽器中,在創建socket之后??梢酝ㄟ^onopen,onmessage,onclose即onerror四個事件實現對socket進行響應

一個簡單是示例

var ws = new WebSocket(“ws://localhost:8080”);ws.onopen = function(){  console.log(“open”);  ws.send(“hello”);};ws.onmessage = function(evt){  console.log(evt.data)};ws.onclose = function(evt){  console.log(“WebSocketClosed!”);};ws.onerror = function(evt){  console.log(“WebSocketError!”);};

1.var ws = new WebSocket(“ws://localhost:8080”);

申請一個WebSocket對象,參數是需要連接的服務器端的地址,同http協議使用http://開頭一樣,WebSocket協議的URL使用ws://開頭,另外安全的WebSocket協議使用wss://開頭。

ws.send(“hello”);

用于叫消息發送到服務端

 

2.ws.onopen = function() { console.log(“open”)};

當websocket創建成功時,即會觸發onopen事件

 

3.ws.onmessage = function(evt) { console.log(evt.data) };

當客戶端收到服務端發來的消息時,會觸發onmessage事件,參數evt.data中包含server傳輸過來的數據

 

4.ws.onclose = function(evt) { console.log(“WebSocketClosed!”); };

當客戶端收到服務端發送的關閉連接的請求時,觸發onclose事件

 

5.ws.onerror = function(evt) { console.log(“WebSocketError!”); };

如果出現連接,處理,接收,發送數據失敗的時候就會觸發onerror事件

我們可以看出所有的操作都是采用事件的方式觸發的,這樣就不會阻塞UI,使得UI有更快的響應時間,得到更好的用戶體驗。

 

服務端

現在有很多的服務器軟件支持websocket,比如node.js,jetty,tomcat等

這里我使用的是tomat 7.0和eclipse4.2

在tomcat下使用websocket首先需要導入相關的jar

tomcat7提供的與WebSocket相關的類均位于包org.apache.catalina.websocket之中(包org.apache.catalina.websocket的實現包含于文件catalina.jar之中

 

這里我們把tomcat的全部導入就行了

在build path->configure build path->librarise->add library->server runtime->apache tomcat v7.0

image

 

 

同時需要import以下包

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WsOutbound;
import org.apache.catalina.websocket.WebSocketServlet;

 

我們需要兩個類

第一個用于處理websocket請求

第二個用于處理每一次具體的WebSocket任務

 

第一個類


public class SocketServer extends WebSocketServlet {
    private static final long serialVersionUID = 1L;
    //……
    @Override
    protected StreamInbound createWebSocketInbound(String arg0,
            HttpServletRequest arg1) {
        // TODO Auto-generated method stub
        return new ChatWebSocket(users);
    }
}



這個Servlet繼承自WebSocketServlet,實現createWebSocketInbound方法。該方法返回第二個類的實例。

 

第二個類


public class ChatWebSocket extends MessageInbound {

        @Override
        protected void onTextMessage(CharBuffer message) throws IOException {

        }

        @Override
        protected void onOpen(WsOutbound outbound) {
            
        }

        @Override
        protected void onClose(int status) {
            

        }

        @Override
        protected void onBinaryMessage(ByteBuffer arg0) throws IOException {

        }
//其余略

    }



 

protected void onTextMessage(CharBuffer message) throws IOException { }

文本消息響應

protected void onBinaryMessage(ByteBuffer arg0) throws IOException { }

二進制消息響應

protected void onOpen(WsOutbound outbound) { }

建立連接的觸發的事件

protected void onClose(int status) { }

關閉連接時觸發的事件

 

 

 

 

4.程序代碼

html部分


<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/socket.js"></script>
<title>無標題文檔</title>
</head>
<script language="javascript">

</script>
<body>
<table>
  <tr>
    <td>Message</td>
    <td><input type="text" id="message"></td>
  </tr>
  <tr>
    <td>Name</td>
    <td><input type="text" id="othername"></td>
  </tr>
  <tr>
    <td><input id="sendbutton" type="button" value="send" onClick="click"  disabled="true">
      </input></td>
  </tr>
</table>
<script>

</script>
</body>
</html>



 

js部分(關于jquery部分不進行講解)


var username = window.prompt("輸入你的名字:");

document.write("Welcome<p id=/"username/">"+username+"</p>");

if (!window.WebSocket && window.MozWebSocket)
    window.WebSocket=window.MozWebSocket;
if (!window.WebSocket)
    alert("No Support ");
var ws;

$(document).ready(function(){
    
     $("#sendbutton").attr("disabled", false);
     $("#sendbutton").click(sendMessage);

    startWebSocket();
})

function sendMessage()
{
    var othername=$("#othername").val();
    var msg="MSG/t"+username+"_"+othername+"_"+$("#message").val();
    send(msg);
}
function send(data)
{
    console.log("Send:"+data);
    ws.send(data);
}
function startWebSocket()
{    
    ws = new WebSocket("ws://" + location.host + "/WebSocket/SocketServer");
    ws.onopen = function(){
        console.log("success open");
        $("#sendbutton").attr("disabled", false);
    };
     ws.onmessage = function(event)
     {
         console.log("RECEIVE:"+event.data);
         handleData(event.data); 
     };
      ws.onclose = function(event) { 
    console.log("Client notified socket has closed",event); 
  }; 
  
}

function handleData(data)
{
    var vals=data.split("/t");
    var msgType=vals[0];
    switch(msgType)
    {
    case "NAME":
        var msg=vals[1];
        var mes="NAME"+"/t"+msg+"_"+ username;
        send(mes);
        break;
    case "MSG":
        var val2s=vals[1].split("_");
        var from=val2s[0];
        var message=val2s[2];
        alert(from+":"+message);
        break;
    default:
        break;
            
    }
}



java部分


import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;

import javax.servlet.http.HttpServletRequest;
import java.util.Set;


import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WsOutbound;
import org.apache.catalina.websocket.WebSocketServlet;



public class SocketServer extends WebSocketServlet {
    private static final long serialVersionUID = 1L;
    public final Set<ChatWebSocket> users = new CopyOnWriteArraySet<ChatWebSocket>();

    public static int USERNUMBER = 1;
    @Override
    protected StreamInbound createWebSocketInbound(String arg0,
            HttpServletRequest arg1) {
        // TODO Auto-generated method stub
        return new ChatWebSocket(users);
    }
    public class ChatWebSocket extends MessageInbound {

        private String username;
        private Set<ChatWebSocket> users = new CopyOnWriteArraySet<ChatWebSocket>();;

        public ChatWebSocket() {

        }

        public ChatWebSocket(Set<ChatWebSocket> users) {
            this.users = users;
        }

        @Override
        protected void onTextMessage(CharBuffer message) throws IOException {
            // 這里處理的是文本數據
        }

        public void onMessage(String data) {
            String[] val1 = data.split("//t");
            if(val1[0].equals("NAME"))
            {
                String[] val2=val1[1].split("_");
                for(ChatWebSocket user:users){
                    if (user.username.equals(val2[0])){
                        user.username=val2[1];
                    }
                }
            }
            else if(val1[0].equals("MSG"))
            {
                String[] val2=val1[1].split("_");
                for(ChatWebSocket user:users){
                    if (user.username.equals(val2[1])){
                        try {
                            CharBuffer temp=CharBuffer.wrap(data);
                            user.getWsOutbound().writeTextMessage(temp);
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }        
            }
            else
            {
                System.out.println("ERROR");
            }

        }

        @Override
        protected void onOpen(WsOutbound outbound) {
            // this.connection=connection;
            this.username = "#" + String.valueOf(USERNUMBER);
            USERNUMBER++;
            try {
                String message = "NAME" + "/t" + this.username;
                CharBuffer buffer = CharBuffer.wrap(message);
                this.getWsOutbound().writeTextMessage(buffer);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            users.add(this);
        }

        @Override
        protected void onClose(int status) {
            users.remove(this);

        }

        @Override
        protected void onBinaryMessage(ByteBuffer arg0) throws IOException {

        }

    }
    
}
 

解釋

這里我的想法是

1 每個用戶在訪問的時候首先需要輸入自己的名字,接著向服務端發送連接請求

2 服務端在接受到客戶端的連接請求后,會new ChatWebSocket(users);用于處理這個請求,并把它加入在線的用戶列表中,由于這個時候,服務端尚不知道客戶的名字。它會給這個用戶假定一個名字,#1,然后服務端會發送"NAME" + "/t" +“#1”給客戶端,你叫什么?

3 客戶端收到這個消息會知道,服務器在問自己叫什么名字,于是客戶端會發送"NAME"+"/t"+“#1”+"_"+ 自己的名字到服務端,(我叫xxx)

4 服務端收到這個消息后根據#1在當前在線的用戶列表中進行查找,將#1替換為客戶的名字,這樣服務端就知道了這個客戶的名字了

5 當客戶離開時,服務端會觸發onClose事件,服務端會把當前用戶從在線列表中移除

用圖畫出來類似這樣(畫的不好,—_—!!)

html5利用websocket完成的推送功能

代碼

js

ws = new WebSocket("ws://" + location.host + "/WebSocket/SocketServer");

 

連接服務端

 

java

protected StreamInbound createWebSocketInbound(String arg0,
            HttpServletRequest arg1) {
        // TODO Auto-generated method stub
        return new ChatWebSocket(users);
    }

創建一個chatwebsocket用于處理這個請求,觸發該chatwebsocket對象的onOpen事件


@Override
    protected void onOpen(WsOutbound outbound) {
        // this.connection=connection;
        this.username = "#" + String.valueOf(USERNUMBER);
        USERNUMBER++;
        try {
            String message = "NAME" + "/t" + this.username;
            CharBuffer buffer = CharBuffer.wrap(message);
            this.getWsOutbound().writeTextMessage(buffer);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        users.add(this);
    }



為這個客戶假定一個姓名,并發送NAME+“/t”+假定的姓名  給該客戶端,同時將該客戶端加入當前連接的客戶列表中

 

js


function handleData(data)
{
    var vals=data.split("/t");
    var msgType=vals[0];
    switch(msgType)
    {
    case "NAME":
        var msg=vals[1];
        var mes="NAME"+"/t"+msg+"_"+ username;
        send(mes);
        break;
   //………            
    }
}



接受并處理服務端發來到的消息,發現是服務端問自己叫什么名字,于是發送”NAME"+"/t"+假定的名字+"_"+ 真正的名字 給服務端

 

 

java


public void onMessage(String data) {
        String[] val1 = data.split("//t");
        if(val1[0].equals("NAME"))
        {
            String[] val2=val1[1].split("_");
            for(ChatWebSocket user:users){
                if (user.username.equals(val2[0])){
                    user.username=val2[1];
                }
            }
        }

//………
}



處理并接受客戶端發來的消息,發現是客戶端回復自己叫什么名字,于是在根據先前假定的名字在當前連接的客戶列表中進行查找,將假名變成真名

 

js

function sendMessage()
{
    var othername=$("#othername").val();
    var msg="MSG/t"+username+"_"+othername+"_"+$("#message").val();
    send(msg);
}

客戶對另一個人發起對話,消息格式為:“MSG”+自己的名字+_+對方的名字+_+消息

 

 

java


public void onMessage(String data) {
       ///…………
        else if(val1[0].equals("MSG"))
        {
            String[] val2=val1[1].split("_");
            for(ChatWebSocket user:users){
                if (user.username.equals(val2[1])){
                    try {
                        CharBuffer temp=CharBuffer.wrap(data);
                        user.getWsOutbound().writeTextMessage(temp);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }        
        }
       ///…………

    }



發現是客戶發送的消息,根據對方的姓名,在當前連接的客戶列表中查找,并將消息發給他

 

 

js


function handleData(data)
{
    var vals=data.split("/t");
    var msgType=vals[0];
    switch(msgType)
    {
    ///…

    case "MSG":
        var val2s=vals[1].split("_");
        var from=val2s[0];
        var message=val2s[2];
        alert(from+":"+message);
        break;
    default:
        break;
            
    }
}



發現是另一個客戶發來的消息,通過alert顯示出來

 

java

@Override
        protected void onClose(int status) {
            users.remove(this);

        }

發現客戶離開了,將客戶從連接的客戶列表中移除

可以改進的地方

1.若客戶端A發送消息給B時,B不在線,可將消息存入數據庫中,當發現B上線時,從數據庫中取出,發送給B

2 服務端發送你叫什么時,可加入超時機制,若客戶端一定時間內沒有回復自己叫什么,則可將該客戶從在線列表中刪掉

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲视频精品在线| 成人黄色免费片| 精品国产一区二区三区久久| 97在线视频精品| 欧美孕妇与黑人孕交| 亚洲精品福利在线观看| 日韩欧美黄色动漫| 亚洲欧美日本精品| 国产成人在线一区| 国产中文日韩欧美| 欧美黑人xxx| 日本午夜精品理论片a级appf发布| 日韩电视剧在线观看免费网站| 久久免费视频这里只有精品| 亚洲第一福利视频| 国产精品久久久久久久久久| 777午夜精品福利在线观看| 国产精品中文久久久久久久| 久久亚洲精品国产亚洲老地址| 国产成人精品亚洲精品| 国产精品久久久久久久7电影| 精品视频在线导航| 国产精品亚发布| 国产一区二区三区在线观看网站| 国产欧美在线看| 性日韩欧美在线视频| 疯狂做受xxxx欧美肥白少妇| 91免费精品国偷自产在线| 国产日韩欧美日韩大片| 北条麻妃在线一区二区| 亚洲自拍偷拍一区| 国产精品日韩电影| 中文字幕亚洲欧美一区二区三区| 日韩欧美精品中文字幕| 国产女人18毛片水18精品| 这里只有视频精品| 久久五月天色综合| 精品国产欧美一区二区五十路| 国产精品午夜一区二区欲梦| 国产亚洲aⅴaaaaaa毛片| 欧美肥老妇视频| 日韩亚洲精品电影| 日本19禁啪啪免费观看www| 欧美在线亚洲一区| 日本精品免费观看| 91精品国产高清久久久久久91| 国产精品爽爽爽爽爽爽在线观看| 国产日韩欧美视频| 国产一区二区丝袜高跟鞋图片| 国产精品久久久久久久久久99| 亚洲视频网站在线观看| 国产精品久久久久久久一区探花| 亚洲精品成a人在线观看| 夜夜狂射影院欧美极品| 亚洲午夜久久久影院| 97国产精品免费视频| 狠狠色狠狠色综合日日五| 亚洲欧美中文字幕在线一区| 欧美激情亚洲综合一区| 亚洲最大福利网| 国产精品第三页| 成人看片人aa| 亚洲成人免费网站| 亚洲欧洲第一视频| 国产伦精品免费视频| 精品久久久久久久中文字幕| 精品少妇一区二区30p| 91国内精品久久| 成人免费淫片视频软件| 91免费国产视频| 亚洲一区二区国产| 日韩视频免费中文字幕| 亚洲一品av免费观看| 欧美黑人xxxx| 亚洲九九九在线观看| 91成人国产在线观看| 久久成人在线视频| 亚洲人成网站免费播放| 亚洲精品一区二三区不卡| 久久精品国产欧美亚洲人人爽| 亚洲欧美三级伦理| 欧美激情videos| 久久精品一偷一偷国产| 亚洲sss综合天堂久久| 午夜精品视频网站| 国产精品久久久久久久久久东京| 成人有码视频在线播放| 亚洲成人久久网| 亚洲日本中文字幕免费在线不卡| 国产激情视频一区| 久久国产色av| 成人在线观看视频网站| 91久久久久久久久| 国产精品a久久久久久| 九九热这里只有在线精品视| 97涩涩爰在线观看亚洲| 久久久精品一区| 久久91精品国产91久久跳| 国产视频久久久久久久| 日韩精品视频观看| 九九视频直播综合网| 欧美一级片免费在线| 欧美老少做受xxxx高潮| 91精品国产高清自在线看超| 国产一区欧美二区三区| 色偷偷亚洲男人天堂| 久久精品国产久精国产思思| 国产日韩综合一区二区性色av| 91超碰中文字幕久久精品| 奇米四色中文综合久久| 国产精品久久不能| 国产精品99久久久久久人| 亚洲美女又黄又爽在线观看| 亚洲精品国产综合久久| 91免费国产视频| 欧美激情乱人伦一区| 91av成人在线| 亚洲欧洲国产伦综合| 久久亚洲一区二区三区四区五区高| 久久躁日日躁aaaaxxxx| 国产免费一区二区三区在线观看| 久热精品视频在线| 国产精品视频午夜| 国内精品久久久久影院优| 国产成人在线一区二区| 亚洲福利在线看| 欧美亚洲国产视频| 亚洲a区在线视频| 欧美中文字幕在线播放| 欧美中文字幕精品| 欧美一级电影免费在线观看| 成人免费淫片视频软件| 欧美精品一区二区免费| 欧美在线播放视频| 国产在线999| 欧美激情aaaa| 国产精品私拍pans大尺度在线| 久久九九有精品国产23| 亚洲欧美国产高清va在线播| 欧美做爰性生交视频| 亚洲午夜久久久久久久| 亚洲精品网站在线播放gif| 狠狠综合久久av一区二区小说| 亚洲精品美女在线观看播放| 成人信息集中地欧美| 激情亚洲一区二区三区四区| 欧美日韩福利视频| 亚洲第一精品电影| 欧美日产国产成人免费图片| 久久九九有精品国产23| 欧美国产乱视频| 久久久久久com| 亚洲综合最新在线| 国产91精品黑色丝袜高跟鞋| 欧美午夜性色大片在线观看| 欧美理论电影在线播放| 久久久久亚洲精品| 亚洲片国产一区一级在线观看| 亚洲乱码av中文一区二区| 2021久久精品国产99国产精品| 欧美性xxxxxx| 亚洲成年人在线播放| 97婷婷涩涩精品一区| 久久久99久久精品女同性|