2012-11-16 120 views
10

我可以在websockets上從服務器發送和接收消息。我需要編寫一個函數將數據發送到服務器,並等待來自服務器的響應,然後將其作爲函數的結果返回。帶Websockets的同步請求

發送:

ws.send('my_message_to_server'); 

接收(這是一個事件):

ws.bind('message', function(message) { 
console.log(message); 
}); 

我的功能:

function request(message){ 
ws.send(message); 
    //How wait for receive??? 
    return response; 
} 
+0

你不能做的東西異步同步功能。忙碌的等待是糟糕的,JavaScript不支持它。你爲什麼想要這樣做?看看承諾。 – Bergi

+0

@Bergi其實你可以。看看下面的答案。只是創建一個簡單的隊列,沒有在這個例子中等待:) –

+0

@RonanDejhero:不,你的功能不同步。它確實使用異步回調,因爲每個套接字偵聽器都需要。 – Bergi

回答

3

當您創建的WebSocket,你通常添加的onMessage回調函數到客戶端從服務器接收數據時調用的套接字。

var socket = new WebSocket("ws://example.com:8000/websocketapp.php"); 
socket.onmessage = function(msg){ 
     alert('The server says: ' + msg); 
} 

該塊,直到服務器響應是一個壞主意概念,因爲它意味着腳本的執行將掛起,直到從服務器的應答進來的功能。當服務器繁忙,網絡延遲高這可能需要幾秒鐘的時間。因此,最好使用回調函數(在發生事件時調用的函數)。

當你能保證你每次只向服務器發送一個請求,你可以改變socket.onmessage功能來處理該服務器響應,並作用於它的功能:

socket.onopen = function() { 
    socket.send("What's your name?"); 
    socket.onmessage = function(message) { 
     alert("The server says its name is " + message); 
     socket.send("What is the answer to life, the universe and everything?"); 
     socket.onmessage = function(msg){ 
      alert("The server says the answer is: " + msg); 
     } 
    } 
} 

(順便說一句:在設置回覆處理程序以提高可讀性之前,我編寫了請求,最好是以相反的方式執行:先設置回覆處理程序然後發送請求,這對於不太可能的但不是不可能的如果服務器響應速度太快以至於尚未設置處理程序)。

但是,當你有多個並行請求,你需要找出服務器指向哪個請求時,你需要更好的東西。例如,您可以使用onmessage函數來標識消息,然後將每個消息轉發給專門的消息處理函數。

+0

你可能是指'socket.send()'? – Christoph

+0

是的,我喜歡。謝謝,我糾正了這個錯誤。 – Philipp

+0

如果服務器在服務器端發生某些事情時將某些信息「推回」客戶端,該怎麼辦?這段代碼如何工作?它不會! –

2

你應該在WebSockets上使用某種RPC協議。我建議你看看WAMP這是一個WebSocket子協議,它增加了RPC和PUB/SUB語義。它包括一個客戶端庫,它通過給你一個基於承諾的API來在一定程度上抽象異步連接。

下面是一個例子:

var wsuri = "ws://localhost:9000"; 

ab.connect(wsuri, function (session) { 
    session.call("http://example.com/simple/calc#add", 23, 7).then(
     function (res) { 
      console.log("got result: " + res); 
     }, 
     function (error, desc) { 
      console.log("error: " + desc); 
     } 
    ); 
}); 

有許多服務器端實現的用於此的。

1

WebSocket就像TCP一樣,它只是一個傳輸層。你需要的是在webSocket上運行一個協議。該協議負責爲您創建消息之間的相關性。您可能想看看AMQP,它是實時異步消息的最廣泛和最完整的開放協議。有關簡單的AMQP客戶端JS庫,請參閱https://github.com/dansimpson/amqp-js

我不知道您使用的服務器類型,但AMQP將爲您提供最大的靈活性,因爲AMQP在很多平臺上都有很多支持。還有簡單的AMQP消息代理實現。如果你的服務器是Java,那麼你會想看看JMS。在這種情況下,您將需要一個更加複雜而強大的JMS代理。

9

前段時間我在一些在線遊戲中使用了一種簡潔的方式,但是您還需要更改服務器端的東西!

1日做一個函數來發送數據

var socketQueueId = 0; 
var socketQueue = {}; 

function sendData(data, onReturnFunction){ 
    socketQueueId++; 
    if (typeof(returnFunc) == 'function'){ 
     // the 'i_' prefix is a good way to force string indices, believe me you'll want that in case your server side doesn't care and mixes both like PHP might do 
     socketQueue['i_'+socketQueueId] = onReturnFunction; 
    } 
    jsonData = JSON.stringify({'cmd_id':socketQueueId, 'json_data':data}); 
    try{ 
     webSocket.send(jsonData); 
     console.log('Sent'); 
    }catch(e){ 
     console.log('Sending failed ... .disconnected failed'); 
    } 
} 
在服務器端

然後,處理請求時,你應該送cmd_id回客戶端的響應

webSocket.onmessage = function(e) { 

    try{ 
     data = JSON.parse(e.data); 
    }catch(er){ 
     console.log('socket parse error: '+e.data); 
    } 

    if (typeof(data['cmd_id']) != 'undefined' && typeof(socketQueue['i_'+data['cmd_id']]) == 'function'){ 
     execFunc = socketQueue['i_'+data['cmd_id']]; 
     execFunc(data['result']); 
     delete socketQueue['i_'+data['cmd_id']]; // to free up memory.. and it is IMPORTANT thanks Le Droid for the reminder 
     return; 
    }else{ 
     socketRecieveData(e.data); 
    } 
} 

和創建一個函數來處理所有其他類型的回報:

socketRecieveData(data){ 
    //whatever processing you might need 
} 

so now simp LY,如果你想發送一些數據服務器並等待響應你簡單做,具體的數據:

sendData('man whats 1+1', function(data){console.log('server response:');console.log(data);}); 
+0

哇,真是個好主意!我花了一些時間來理解,但是將回調發送到服務器並將其回送給客戶端非常出色。 – Benvorth

+1

我一直在尋找這個確切的解決方案太懶惰,無法重新發明輪子。非常優雅和靈活。 'i_'是可選的,因爲字典也可以使用int。在execFunc調用釋放內存後,可以添加以下內容: delete socketQueue ['i _'+ data ['cmd_id']]; –