2012-11-16 72 views
10

ウェブサーバー上でサーバーからメッセージを送受信できます。私は、サーバーにデータを送信し、サーバーからの応答を待っていて、関数の結果としてそれを返す関数を書く必要があります。WebSocketを使用した同期要求

送る:

ws.send('my_message_to_server'); 

が(それはイベントです)を受信:

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

My機能:あなたはのWebSocketを作成するとき

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

非同期の機能は使用できません。忙しい待っている、とJavaScriptはそれをサポートしていません。なぜそうしたいのですか?約束を見てください。 – Bergi

+0

実際に@Bergiできます。下の私の答えを見てください。シンプルなキューを作成してください。その例ではビジー待機しません:) –

+0

@RonanDejhero:いいえ、あなたの関数は同期していません。すべてのソケットリスナーが必要とするので、非同期コールバックを使用します。 – Bergi

答えて

3

、あなたは、通常のonMessageコールバック関数を追加クライアントがサーバからデータを受信するたびに呼び出されるソケットに送信します。

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

それは、サーバからの応答が入って​​来たまで、スクリプトの実行がハングアップすることを意味するので、概念的に悪い考えであるブロックサーバーが応答するまで。サーバーがビジー状態とネットワーク遅延が高い場合の機能これには数秒かかることがあります。そのため、コールバック関数(イベントが発生したときに呼び出される関数)を使用する方がよいでしょう。

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); 
     } 
    } 
} 

:あなたが唯一のサーバーに一度に一つのリクエストを送信することを保証することができた場合

は、あなたはそれの上のサーバーの応答を処理し、動作機能にsocket.onmessage機能を変更することができます(ちなみに:私はより良い可読性のために返信ハンドラを設定する前にリクエストを書いていましたが、それ以外の方法をとる方が良いでしょう:まず返信ハンドラを設定してからリクエストを送信してください。サーバが非常に速く応答して、ハンドラがまだ設定されていない場合)。

しかし、複数の並列要求があり、サーバーが参照している要求を見つける必要がある場合は、より良いものが必要です。たとえば、メッセージを識別し、各メッセージを特殊なメッセージハンドラ関数に転送するonmessage関数を使用できます。

+0

あなたはおそらく 'socket.send()'を意味しますか? – Christoph

+0

はい、あります。ありがとう、私は間違いを訂正しました。 – Philipp

+0

サーバ側で何か起きたときに、サーバが何らかの情報をクライアントに「プッシュ」すればどうなるでしょうか?このコードはどのように機能しますか?それはしません! –

2

WebSocketの上に何らかのRPCプロトコルを使用する必要があります。私はあなたがRPCとPUB/SUBセマンティクスを追加するWebSocketサブプロトコルであるWAMPを見てみることをお勧めします。これには、約束した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

私は少し前にオンラインゲームで使った方法はありますが、サーバー側でも変更する必要があります。

第一は、要求を処理するときに、サーバ側では、あなたが応答

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); 
    } 
} 

で、クライアントにcmd_idを送るべきデータ

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'); 
    } 
} 

を送信する機能を作成し、他のすべてのタイプのリターンを処理する関数を作成します。

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

so simpサーバーのデータを送信して、単純なデータの応答を待つ場合は、

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

うわー、本当に良いアイデア!理解するのに時間がかかりましたが、コールバックをサーバーに送信してクライアントに戻してもらうことは賢明です。 – Benvorth

+1

私は、この正確な解決策がホイールを再開発するにはあまりにも怠惰であることを探していました。非常にエレガントでフレキシブル。辞書がintでも機能するので、 'i_'はオプションです。 execFuncコールの後にメモリを解放するために次の行を追加することができます。 delete socketQueue ['i _' + data ['cmd_id']]; –

関連する問題