この記事では、「ソケット」という用語は、クライアントが常に「ポートをリッスン」している状態で、サーバーとクライアントのスクリプト間のデータ交換を提供するソフトウェアインターフェイスを意味します。 つまり、サーバー上で何かが発生するとすぐに、クライアントにそのことをすぐに通知できます。 もちろん、javascriptには「ポートをリッスン」して本格的なソケットを作成する方法はありませんが、一方で、マッチ、電気テープ、プラスチシンがあり、そこから何らかの類似性を作ることができます。
最初に、このシステムの動作の大まかな原理を説明し、次に、伝統に基づいて、もちろんリンクを使用して、それに基づいて構築されたプリミティブチャットのコードを提供します。 私は自分の目で行動のhabraeffectを見たいです。 最後に、ソースリポジトリへのリンクがあります。
動作原理
これは、ロングポーリング方式に基づいています。 クライアントモジュールは、サーバースクリプトに要求を送信します。サーバースクリプトは、所定の長い時間を閉じません(この時間は、スクリプトがサーバー上で実行可能な最大時間、たとえば20〜25秒に依存します)。 この間に何も起きなかった場合、スクリプトはこれをクライアントに報告し、動作を停止します。 そのようなメッセージを受け取ったクライアントは、すぐに新しいリクエストを作成します。 これはすべて、クライアントにとって重要な何らかのイベントがサーバーで発生するまで続きます。サーバースクリプトは、定義済みの関数をすぐに起動します。これにより、ハッシュの形式でクライアントへの応答が形成され、返信され、応答がすぐにクライアントに送信されます。 同時に、クライアント自体がイベントを開始してサーバーに情報を送信できます。このポートをリッスンしている他のクライアントは、このイベントについてすぐに知ることができます。
システムは2つのプラグインとして実装されます。 もちろん、クライアント、javascript。 2番目のサーバー側は、perlで記述されています。 モジュール自体の名前、およびそれらによってエクスポートされるすべてのプロパティとメソッド、変数および関数は、音楽愛好家が何かを聞くとすぐに、異なる部屋
("")
で蓄音機を聴く音楽愛好家
( )
との見かけ上面白い類推に触発され
( )
部屋は記録を変更しました-それはあなたの所定の機能のいくつかについてこれについて知らせます。 (これらすべての同義語-アナロジーは、秩序を回復するための私の巨人の努力にもかかわらず、以下のテキスト全体とコードへのコメントで互いにランダムに置き換えられるため、少なくともそれらを覚えておく価値はあります:)
クライアント側:
それは何とかこのように接続します:
<script type="text/javascript" src="MWS_meloman.js"></script>
「リスニング」はListen関数によって開始され、1つのパラメーターが渡されます-形式の文字列
< -> : < >
このポートに何かが到着するとすぐにハンドラー関数が開始され、この「何か」がオブジェクト(property:value、...)としてすぐに渡されます。
例えば
meloman.Listen('handler1:5') // meloman.Listen('handler1:5-7') // meloman.Listen('handler1:5-7; handler2 : 8-10; handler3 : 11-20');
何らかの理由でリスニングを停止する必要がある場合は、空の行を渡す必要があります。
// meloman.Listen(''); // : meloman.Listen(); // , , :)
サーバーが「知る」必要があるものと、このポートをリッスンする人がクライアントに発生した場合、この「何か」をオブジェクトに「パック」し、最初のパラメーターとして「ポート」パラメーターを指定して、それを変更機能に渡します。
例:
var some = { 'name' : 'Mr.Smith', 'message' : 'Find Neo'} meloman.Change( 5, some );
すぐにサーバーに送信され、perl関数に渡されます。perl関数はそれをどう処理するかをハッシュの形式で知っています。
いくつかの設定プロパティがあります。
minReconnectTime-ミリ秒単位の時間。多くの場合、サーバーにリクエストを送信できますが、
reconnectTime-新しいリクエストがサーバーに送信されるまでのミリ秒単位の時間、
waitingTimeOut-サーバーからの応答を待つ最大時間、
waitingTimeOutHandler - waitingTimeOut中にサーバーからの応答がまったく受信されなかった場合の状況を処理する関数、
connectionErrorHandler-サーバーエラーを処理する関数(サーバーからの応答が200 OKでない場合)、
routeToChange -Change関数によってオブジェクトが転送されるサーバースクリプトへのパス、
routeToListen-指定されたポートを「リッスン」し、クライアントに情報を送信するサーバースクリプトへのパス。
ignoreMyChanges -falseの場合、Change関数によって行われた変更はサーバー上の新しいイベントとして認識されます。
これらのすべての設定のうち、 routeToChangeとrouteToListenのみが必須であり、残りはデフォルト設定を持っているか、正しく動作するために重要ではありません。
サーバー側:
Patefon.pmモジュールがダウンロードされ、どこかに、たとえば./libsにコピーされ、接続されます。
use lib "./.libs"; use Patefon;
モジュールは&change_the_plateおよび&listen_the_plate関数と設定ハッシュ%patefons_knobsをエクスポートします。 (ベータ版はもう少し(デバッグ用に)エクスポートしますが、これは次のバージョンで修正される予定です。)
サーバーで、リスニング用とクライアントから情報を「受信」するための2つのスクリプトを作成することをお勧めします。 すべてが単一のスクリプトに詰め込まれていても、誰も気にしませんが。
「リッスン」するのは&listen_the_plate関数を使用し、パラメーターなしで開始します。 開始する前に、必要なすべてのポートにハンドラー関数を指定する必要があります。
$patefons_knobs{handlers}{< >} = < ->;
たとえば、次のように:
$patefons_knobs{handlers}{1} = \&handler_1;
このハンドラー関数は、最初のパラメーターを何かが変更された部屋ポート番号として受け入れ、2番目(必要な場合)に新しい再生レコードの番号を受け入れる準備ができている必要があります。 このすべて(および、おそらくこれだけでなく)を実行し、クライアントに送信する必要のあるハッシュを返します。
このすべての前に、「rooms-ports」でフォルダーへのパスを指定する必要があります。
$patefons_knobs{path_to_rooms} = './.rooms/';
各ポートのこのフォルダには同じ名前のフォルダがあり、そのような各フォルダにはドアファイルがあります(そこに書かれているものに関係なく、それはうまくいきます)それは「ポートルーム」をブロックするために使用されますfunction&change_the_plate(クライアントから何かがサーバーに来た瞬間)。
サンプルディレクトリスキーム./.rooms:
./.rooms/ ./1/ ./door ./2/ ./door
など
リッスンしているスクリプトは、 &change_the_plate関数を使用します。 開始する前に、「ポートルーム」へのパスを指定する必要があります。
$patefons_knobs{path_to_rooms} = './.rooms/';
およびハンドラー関数:
$patefons_knobs{ChngHandlers}{<>} = < ->;
関数は、クライアントから送られたハッシュへの参照をハンドラーに渡します。
その後、彼女が彼と何かをした後、彼女は真と解釈できる値、例えば1を返さなければなりません。
また、転送されるすべてのハッシュ/オブジェクトが1次元でなければならないことも重要です。
// , : var some = { 'name' : 'Mr.Smith', 'message' : 'Find Neo!', 'time' : 'Now!' }; // : var some = { 'name' : 'Mr.Smith', 'action' : { 'message' : 'Find Neo!', 'time' : 'Now!' } };
設定のハッシュでは、「ルーム」へのハンドラーとパスを指定することに加えて、次のハンドルをねじることができます。
patefons_knobs {sample_rate} -ポートステータスがポーリングされるまでの秒単位の時間。デフォルトは1。
patefons_knobs {maxSleeping} -リスニングスクリプトがデフォルトで作業を完了するまでの時間(秒単位)20。
すべてのエラーが追加される配列patefons_knobs {errors}があります。エラーなしで実行されたモジュール関数は、 エラー-0で 1を返します。これは、たとえばエラーをログに書き込むために使用できます。 このように、例えば:
unless ( &change_the_plate ) { open LOG, ">>log"; $" = "\n"; print LOG qq(ERRORS: @{$patefons_knobs{errors}}); }
以下は約束されたプリミティブなチャットコードです。 (自動スクロールとサウンドの形式のホイッスルを除く)javascriptには16行しかありません(デフォルト設定が使用されている場合は、一般に14行です)。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> </title> <link rel="stylesheet" href="chat_style.css" type="text/css" media="screen"/> <script type="text/javascript" src="MWS_meloman.js"></script> <script> var mayScroll = true; meloman.ignoreMyChanges = true; meloman.routeToListen = 'ls.pl'; meloman.reconnectTime = 25000; meloman.routeToChange = 'ch.pl'; meloman.Listen('j3:1'); function j3 ( a ) { var string = ''; for ( var Name in a ) { string += Name + "\t" + a[Name] + "\n" } document.getElementById('chat').innerHTML += a['message']; playsound(); scrollchat(); }; function send_message () { var banderol = {}; banderol['message'] = document.getElementById('message').value; banderol['user'] = document.getElementById('user').value || 'Anonymous'; banderol['color'] = document.getElementById('color').value || '#333333'; if ( /\S+/.test( banderol['message'] ) && banderol['message'].length < 500 ) { meloman.Change( 1, banderol) } document.getElementById('message').value = ''; } function scrollchat () { if ( mayScroll ) document.getElementById('chat').scrollTop = 9999; } function playsound () { if ( document.getElementById('need_sound').checked ) { document.getElementById("snd").volume = 0.4; document.getElementById("snd").play(); } } </script> </head> <body> <div id="settings" > <span class="params">: <input type="text" size="20" id="user" autofocus /></span> <span class="params">: <input type="color" value="#00aa00" id="color" /></span> <span class="params">: <input type="checkbox" id="need_sound" /></span> </div> <div id="cont"> <div id="chat" onmouseover="mayScroll=false;" onmouseout="mayScroll=true"></div> <form onsubmit="send_message();return false;"> <div id="message_cont"> <input id="message" type="text" autocomplete="off" value="" spellcheck="false" /> </div> </form> </div> <audio id="snd"> <source src="beep.ogg" type="audio/ogg; codecs=vorbis"> <source src="beep.mp3" type="audio/mpeg"> </audio> </body> </html>
そしてサーバー側:
「リスニング」スクリプト:
#!/usr/bin/perl use strict; use warnings; use lib "./.libs"; use Patefon; $patefons_knobs{handlers}{1} = \&j_1; $patefons_knobs{path_to_rooms} = './.rooms/'; $patefons_knobs{maxSleeping} = 20; listen_the_plate(); sub j_1 { my $new = $_[1]; my $old = ( $new - $_[0] ) < 5 ? $_[0] : ( $new - 5 ); my $unreaden_messages; for ( my $i = ++$old; $i <= $new; $i++ ) { open F, "<utf8", "./general_chat/$i" or next; $unreaden_messages .= <F>; } my %hash = ( 'message' => $unreaden_messages ); return %hash; }
および「レコードの変更」:
#!/usr/bin/perl use strict; use warnings; use lib "./.libs"; use Patefon; $patefons_knobs{path_to_rooms} = './.rooms/'; $patefons_knobs{ChngHandlers}{1} = \&j_1; unless ( &change_the_plate ) { open LOG, ">>log"; $" = "\n"; print LOG qq(ERRORS: @{$patefons_knobs{errors}}); } sub j_1 { my ( $room, $plate, $banderol ) = @_; return 0 if ( ${$banderol}{message} eq '' ); unless ( ${$banderol}{color} =~ /^#[0-9a-f]{3}$|^#[0-9a-f]{6}$/i ) { ${$banderol}{color} = '#FE5590' } # shield < and > for ( ${$banderol}{message}, ${$banderol}{user} ) { s/</</g; s/>/>/g } open F, ">", "./general_chat/$plate"; print F qq(<span class="name" style="color:${$banderol}{color};">${$banderol}{user}</span>: <span class="mess">${$banderol}{message}</span><br />) }
実際のチャットへのリンク:
<彼女はここにいたが、彼女はもうそこにいない。 すみません=)>
おもちゃのチャットに加えて、これらのモジュールは多くの異なるアプリケーションで見つけることができると思います。たとえば、これはすべてマルチユーザー管理パネルで行いました。
「疑似Webソケット」のモジュールのこのシステムはベータ版にすぎず、おそらく非常に粗雑ですが、すでにかなり機能しています。 私はこれまでにバグを発見していません。それを使用する人に期待しています:)
ここでは、bitbucket.orgでソースコードを入手できます。 使用、分岐、バグレポートの作成、または投石。 すべての「石」を集めて、どこかでテープで巻いたり、プラスチシンで貼り付けたり、マッチで戻したり、鼻水で接着したりするのがうれしいです。