ホームページ  >  記事  >  バックエンド開発  >  ソケットマルチユーザー接続のヘルプ

ソケットマルチユーザー接続のヘルプ

WBOY
WBOYオリジナル
2016-06-23 14:23:231316ブラウズ

クライアントとしてフラッシュ、サーバーとして php を使用してソケット アプレットを作成しています。

Flash がサーバーに正常に接続した後に問題が発生しました。すべて正常に通信できます

しかし、複数のユーザーがサーバーに接続できません (たとえば、2 つのフラッシュを開いた場合、2 番目のフラッシュは接続できなくなります)

php ソケットがマルチユーザー接続の問題を解決できるかどうか助けてください


専門家が助けてくれることを願っています


ディスカッション (解決策) への返信

誰かが同様のものを開発しましたか?

あなたの PHP プログラムは通常、HTTP リクエストを処理し、応答しますか?それとも本当にソケットサーバーなのでしょうか?

後者の場合、PHP プログラムはどのように開始されますか?

後で議論する前に、これらについて明確に説明する必要があります。

実際のソケット応答が必要です
Flash は常に php に接続されています

php
永久に実行するには
set_time_limit(0);
ignore_user_abort(); を使用できます
ただし、Java で記述する方が良いです
Java を知りません

私の 2 つの質問のうち、最初の質問にしか答えられませんでした。 2 番目の質問は、PHP をどうやって始めるのですか?

開始する前に HTTP リクエストを手動で送信する場合は、PHP の固定ポートを使用して複数のソケット接続リクエストを受信して​​処理する必要があります。これには特定のスキルが必要です。

FLASH がこの HTTP リクエストを送信して開始すると、PHP の別のポートを使用してソケット接続を受信できます。

いずれにせよ、この方法で実行される PHP プログラムはソケットサーバーには適していません。

良いアドバイス

ソケットサーバーを起動するにはフラッシュを使用してください

ただし、起動後の実行時間を制御することはできません (永続的に実行すると、最終的にダウンするまでサーバーに多くのオーバーヘッドが発生します)
また、新しいユーザーが入った 以前にログインしたことのある他のユーザーに積極的に情報を送信する必要がある場合がありますが、それを実現するのは簡単ではありません

前の質問に答えると、PHP の起動では、入る前に PHP を使用してサーバーに接続します。接続できない場合はリクエストしてください (これは私が以前考えていたことです)

確かに、各 FLASH がソケットサーバーとして PHP を起動するように要求した場合、その FLASH のみを提供できるため、実現が困難になります。複数のセッションの相互運用性。

実際のアプリケーションの背景がわからないので、なぜソケットを使用する必要があるのか​​わかりません。通信方法が通常の HTTP に戻せるのであれば、それが最も単純なはずです。


ソケットを使用する必要がある場合は、別の方法への変更を検討することをお勧めします。 Java を使用すればよいというわけではありません。Java を Web モードでデプロイする場合でも、問題は同じです。 PHP は CLI を使用して実行することもできます。

HTTP 経由で接続します。つまり、IIS、APACHE を介して接続します。複数のユーザーを処理する優れた機能があります。

したがって、可能であれば、WEBSERVICE、つまり、IIS、APACHE、


を使用します。つまり、FLASH に関してはオンラインです。教科書には、WEBSERVICEを使うように書いてあります

そうしないと、SERVERをセットアップしてうまく処理できないと、行き詰ってしまいます

主な目的は、WebをベースにしたFlashゲームを作ることです。 1 つの部屋で複数人でプレイできます

各ユーザーに他のユーザーの状況を即座に通知できるようにするには、即時コミュニケーションの目的を達成するためにソケットを使用する必要があります


CLI はまだ使用されていません。例をあげてください?
仕組みと何ができるのか知りたい

アプリケーションシナリオの鍵は「即時通知」ですよね?

ソケットを使用すれば確かに目標を達成できますが、実装は簡単ではありません。少なくとも Web コンテナでは手間がかかります。


実際、HTTP の長い接続を使用しても同じ効果が得られます。たとえば、Kaixin.com にアクセスすると、未完了の HTTP リクエストが常に存在します。これは最大 30 秒で終了しますが、別のリクエストが発生します。これは「即時通知」で実現できます。関連情報については、「彗星ロングコネクション」で検索してください。

(上記の 30 秒は、通知ごとに 30 秒待つ必要があるという意味ではないことに注意してください。通知がない場合は 30 秒後に新しい接続が使用されますが、通知がある場合は、新しい接続が使用されます。すぐに戻ってください)

CLI は、PHP プログラムを起動して実行するもう 1 つの方法であり、この exe が PHP で書かれていることを除けば、サーバー上で直接 exe を実行するのと同じです。 Webコンテナには制限がないため、マルチスレッドやネットワーク通信などの機能をより自由に利用できます。

php
set_time_limit(0);
ignore_user_abort();
を使用して永久に実行することができます

でも、Java を知りません
なぜignore_user_abort()、phpソケットサーバーがあるのですかコマンドラインに含める必要があります
http://devzone.zend.com/article/1086

maquan さん、ありがとうございます

PHP は .exe 接尾辞が付いた実行可能ファイルを作成できますか?

それとも、ファイルも .php であり、起動スタイルが変更されただけなのでしょうか?

http://devzone.zend.com/article/1086 上記の書き方はマニュアルのsocket_selectと似ています

もう一度試してみます

お世話になります!

これまで理解していなかった多くの知識といくつかの解決策を学びました!

改めて感謝します

CLI は、PHP プログラムを起動して実行するもう 1 つの方法であり、この exe が PHP で書かれていることを除けば、サーバー上で直接 exe を実行するのと同じです。 Webコンテナには制限がないため、マルチスレッドやネットワーク通信などの機能をより自由に利用できます。


cli モードで実行するとスレッド制限はなくなりますか?
前に書いたコードは直接実行できるということでしょうか?

皆さん、本当にありがとうございます。オンラインで複数人が参加できるようになりました

即時性がとても良い感じです

maquan さんと BooJS さん、ありがとうございます

投稿後もチャットを続けてもいいですか?

まだチャットしたいですか?

このトピックに関連する限り、急いで投稿を終了しないでください。お気軽にチャットを続けてください。ふふ

ただし、他の質問の場合は、別の投稿を開くのが最善です。誰にとっても読みやすくなります。 CSDN は公共の場所です :)

昨日スペースにアップロードしたとき、cli での実行には 30 秒の制限があり、タイムアウトになることがわかりました。

次に、それを保護し、タイムアウトが検出されたときに cli モードで再度実行するプログラムを作成する必要があります

それでは、try catch を使用してタイムアウトを監視し、catch 内の内容を実行できますか?
try{
私のソケットコード
}
catch(){
再リクエスト
}

catch 括弧の中はどう書けばいいですか?

私はそのスペースとその管理上の制限についてあまり知りません。 PHP 独自の実行時間制限は set_time_limit() を通じて設定できます。デフォルトは 30 秒です。

デーモンのリロードを使用しても問題はうまく解決しない可能性があり、サーバーのパフォーマンスが非常に不安定になり、クライアントの開発がより困難になります。

スペースを借りている場合、型破りなプログラムには多くの制限があることは間違いありません。長時間の接続をよく検討することを強くお勧めします。

わかりました、ありがとうございます

このスペースでは確かに 30 秒のタイムアウトが設定されています
まずは長い接続について勉強しましょう!

これにより、環境要件がはるかに小さくなります

1 日かけて理解した後、コメット ロング コネクションが何なのかを大まかに理解しました。

主に
flash(); を書きます
フロントデスクの ajax が情報を受信できるようにバッファを更新します

同時に、php 側の動作は停止しません

30 秒のタイムアウトが発生しても、クライアントはまた再接続します

私の理解が正しいかわかりません?

正しく理解していますね、基本的にはそういう意味です。

しかし、実装の詳細に集中しすぎる可能性があります。概念的に言うと、いわゆる長時間接続とは、サーバーが HTTP リクエストを受信した後、すぐには完了せず、通知がある場合は一定期間 (30 秒など) 維持することを意味します。すぐに配信する必要がある場合は、応答内容がすぐに出力され、接続が閉じられます。すべてが正常であれば、時間になると戻ります (コンテナーによって強制終了されるまで待たないことをお勧めします)。これにより、クライアントに完全な応答が得られ、クライアントが次の作業を続行しやすくなります。

長い接続を実装する際の難しさの 1 つは、待機プロセス中に「すぐに配信する必要がある通知」をどのように取得するかです。特にスペースを借りる Web コンテナーでは、単純なポーリングと遅延の実装は間違いなく非常に効率的です。さらに悪いことに、何らかのブロッキング IO を使用する方がよいでしょう。


??????????????????????????????????????????? ??????????????????????????????????????????? ??????????????????????????????????????????? ??????????????????????????????????????????? ?????????? the the the down the down down
CSDN フォーラムのファイル ツールが提供するプラグイン拡張機能に基づいて署名を作成しました。みんなで共有してください。技術的な交流を歓迎します :)

確かに、待機プロセス中に、返さなければならない新しいコンテンツがあることをどうやって知るかは面倒な事です
下手をすると即時性に影響します

あればこう思います
返される必要があるコンテンツは、別のユーザーによって読み取られます。 接続が開始されると、ページによって作成された XML または PHP 配列は、ファイルの現在の変更時刻を記録し、変更時刻になったらファイルのコンテンツを返します。変化します。
これにより、変更と接続が同時に行われるなどの問題が発生するかどうかはわかりません (接続する 1 秒前にファイルが変更されているため、次回ファイルが変更されたときにのみ情報が返されます。その可能性はあります)

あなたが言及している IO 操作がよくわかりません



ソケットの小さな例を書きました。私のブログで確認できます。

http://blog.csdn.net/a82168506/article/details/6307461


上の階の兄弟のおかげで、私もソケット用にあなたと同じようなコードを書きました

問題は、スペースに強制 30 秒があることです(set_time_limit(0) は役に立たない)、長い接続がそれを解決できるかどうかを確認するしかありません。


しばらく IO について勉強した後、
長い接続が IO をブロックしているようであることがわかりました。

ノンブロッキング IO を実現したい場合のコツは何ですか?


テストの結果、ajax によって開始された長い接続はノンブロッキング IO であることがわかりました

これは、ブラウザーに長い接続に対する制限があるだけで、同じブラウジングに対して 2 つの長い接続が送信された場合、そのうちの 1 つは接続できません。 !

新しいニュースがあれば、すぐに顧客に通知します

私は次の方法を考えました
または、ファイルを読み取る方法を使用します
まず、ページが開かれると、js が接続を開始し、ファイルの現在の変更時刻を送信します読まれるために

PHP ページに到達します その後、変更時刻が送信された時刻と一致しないことが判明すると、クライアントに新しいメッセージが通知されます
PHP ページが 25 秒間実行されると、ファイルの最終変更時刻がこの長い接続は終了します

js は php を受け取ります 返されたファイルの変更時刻が経過したら、接続を再開し、php によって返されたファイルの変更時刻を送信します

これで必要な情報を見逃すことはないと思いますクライアントに通知されるように

上記は私の個人的な考えです

もう一度助けてください、そしてあなたの処理方法を共有してください

ありがとうございます


...
php ページに到着した後、次のことが判明した場合変更時刻が送信された時刻と一致しない場合、クライアントに新しいメッセージが通知されます
この時点で、ファイルの最終変更時刻が直接 js に返されます。終了
...

赤と青のアクションの間、プログラムは何をしているのでしょうか? 10秒目に「イベントが発生」した場合、間に合うように通知できるでしょうか?


2 つのアクションの間で PHP ページが sleep(1) になり (新しいメッセージを返した後も接続は終了しません)、ファイルの変更時間をチェックします。実行時間が 25 秒を超えるまで接続は終了しません。その後、js によって新しい接続が開始されます

この方法なら問題ありません

もしあなただったら、どうしますか?返す必要がある新しいメッセージがあるかどうかを判断するにはどうすればよいですか?

時間があるときに、フラッシュを取得しましょう


まず第一に、「新しいメッセージを返した後に接続が終了しない」ということは、おそらく問題があります。接続が終了したときにのみ、クライアントは「メッセージを完全に受信した」と判断します。メッセージ「HTTP レスポンス」はさらに処理されます。接続を終了しない場合、フラッシュなどを行ったとしても、データはせいぜいクライアントにストリーミングされるだけですが、クライアントは受信を完了しておらず、処理を開始していません。つまり、通知はまだ行われていません。すぐに"。

「通知の有無を確認する」方法としては、一般的には「ポーリング+遅延」方式に属するものとなりますが、「即時性」と「動作効率」が異なります。わずかに悪い。私は「ブロッキング IO」メソッドの方が良いのではないかと常に感じています。欠点は、少し多くのリソースを消費することです。

レンタルスペースに関しては、Webコンテナの制限があるため仕方がありません。自分の独立したサーバーの場合は、デーモンを取得し、マルチチャネルの非同期 IO を使用し、好きなようにプレイしてください。へへ


????????????????????? ? ??????????

CSDN フォーラムが提供するプラグイン拡張機能をベースに、署名ファイル ツールを作成し、皆さんと共有しました:)


http:// www.zeitoun.net/articles /comet_and_php/start
この例を見つけました

彼は js ライブラリを使用して長い接続を実現し、コンテンツは正常に返され、接続は終了しませんでした。

見てみましょう

私はこの図書館にあまり詳しくありません。この図書館に詳しい友達はいますか?

この彗星は本当の意味でしょうか? 🎜

複数のソースから情報を探しました
、参照できるものが非常に少ないことが分かりました

私の現在のレベルではこの程度しか書けないかもしれません

jsは長い接続を開始します

phpページに新しい情報がある場合、すぐに js に戻り、接続を終了します。 JS はそれを受け取ります。 新しい情報 (処理) 後、すぐに新しい接続を開始します (データ処理前)

25 秒以上新しい情報がない場合、php は接続を終了します。 、js も再び新しい接続を開始します。 れますか?
JSはサーバーに接続するためのソケットクライアントとしても使用できるようですが、複数のクライアントが同時に接続してブロックが発生した場合、クライアントによって開始された接続はタイムアウトになりますか?ソケットサーバーが以前の接続を切断すると、自動的に接続されますか?

理論的に言えば、クライアントの数が多い場合、リアルタイムのパフォーマンスは保証されない可能性があります


私は上記を誤解していたようで、最も一般的な説明を見つけました

たとえば、プロセス A はネットワークからパケットを受信する必要がありますパケットなしで待機している場合はブロックされます。
待たずに他のことをして、パッケージが到着するのを待ってからブロックせずに処理してください。

こうやって見ると

jsは長い接続を開始します
phpページに新しい情報があると、すぐにjsに戻り、JSが新しい情報を受信(処理)した後、接続を終了します。 (データ処理前に) すぐに新しい接続が開始されます
25 秒以上新しい情報がない場合、php は接続を終了し、js も新しい接続を開始します。
これは実際にはブロッキング IO です。新しい情報がない場合、js は新しい情報があるまで常に待機状態を処理します。読み取り操作と書き込み操作の 2 つの段階で「ブロッキング」が使用されます。 「それぞれ。」または「ノンブロッキング」、それぞれに独自の発言権があり、互いに影響しません。

たとえば、サーバーコード: 通知を待つためにsocket_recvfrom()を使用する場合、それは「ブロック」であり、HTTPレスポンスの出力は通常「ブロック」です。 js側でHTTPレスポンスを受信する場合、AJAXを使用しているため「ノンブロッキング」でなければなりません。そうしないとページがフリーズして白い画面になってしまいます。
socket_recvfrom() を使用する場合、サーバーを実行するために cli を使用する必要があります。これにより IO がブロックされますか?
そうではありません。長時間の接続を担当する PHP は、socket_recvfrom() を使用して通知データを待機しており、「ブロックされた状態」になっており、通知データを生成するのは、「ユーザーのログイン」などの別の通常の PHP プログラムである必要があります。はsocket_sendto()を担当します。

理論的には、クライアントの数が多い場合、リアルタイムのパフォーマンスは保証されない可能性があります
心配する必要があるのは「リアルタイムのパフォーマンス」ではありません。上記の通信モデルが成功すれば、リアルタイムのパフォーマンスは保証されます。常に保証されます (もちろんネットワーク速度にも依存します)。問題は、クライアントの数が多い場合、次のようなリソース使用量が比較的大きくなるということです。

· 各クライアントは PHP の長い接続プロセスのリソースを占有し続けます
· 長い接続プロセスごとにソケット リソースを占有します。 ;

一般的に、Web コンテナーに限定すると、このモデルは大規模なアプリケーションには適していません。たとえば、宇宙サービス プロバイダーが Web サイトの同時 HTTP 接続数を制限している場合、接続が長くなると Web サイト全体がダウンする可能性があります。その場合は、「オンライン ユーザー数」と引き換えに「リアルタイム性」を少し落として、「クライアント定期ポーリング」モードに戻す方がよいでしょう。

あなたの方法を試してみましたが、問題が見つかりました

各ポートは 1 つのソケットしか作成できません
ランダムなポートを使用すると、socket_sendto は現在どのポートを送信する必要があるかを認識できません

現在オンラインのリストは必要ですか?ポート?データベースに保存するのとファイルとして保存するのはどちらの方が良いのでしょうか?


UDP ブロードキャストを使用します。具体的な使用方法については情報を確認してください。

わかりました、辛抱強く答えていただきありがとうございます
まず情報を確認します

maquan

ブロードキャストのテストは成功しました

しかし、ブロードキャストにはまだポートを設定する必要があります

コードを貼り付けます


PHP for js request

header("Cache-Control: no-cache, must-revalidate");header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");include('config.php');//这里是$add(IP)和$port$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);socket_bind($socket, $add, $port);//我尝试将$port写为0但是如果这样创建会失败$port = 0;socket_recvfrom($socket, $buf, 10240, 0, $from, $port);echo "Received $buf from remote address $from and remote port $port" . PHP_EOL;socket_close($socket);


ブロードキャストphp
include('config.php');$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, 1); $msg = rand(1000,9999);$len = strlen($msg);socket_sendto($sock, $msg, $len, 0,'255.255.255.255', $port);//这里的$port要和上面那文件的$port相同上面的文件才能收到广播,但是不同客户连接后端口必须不一样才能成功创建socket连接,所以要怎么写才能通知该IP下所有端口的用户呢?这种是通知了端口为$port的所有用户吧socket_close($sock);


すべてのポートに通知するにはどう書けばよいでしょうか?

while (1) にsocket.acceptと書くだけです

Acceptはユーザー接続があるかどうかを監視することです

ユーザー接続は必要なく、sendtoを使用してIPとポートに基づいてオンラインユーザーに送信します

試してください再度socket_set_option ($sock, SOL_SOCKET, SO_REUSEADDR, 1);

还是不行
socket_sendto函数的端口参数不能为空的话接收端就收不到信息,也就是说不能一次性send信息给所有线上的端口

socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1); 应该是写在接收端吧,但是写了也不行

你能写个例子给我吗?

昨天晚上心血来潮,写了一段 UDP 广播通信的程序,正好可以供你参考 :)

recvfrom.php

<?phpheader("Cache-Control: no-cache, must-revalidate");header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");$socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );socket_set_option( $socket, SOL_SOCKET, SO_BROADCAST, 1 );socket_set_option( $socket, SOL_SOCKET, SO_REUSEADDR, 1 );$result = socket_bind( $socket, '0.0.0.0', 9999 );$addr = '';$port = 0;$result = socket_recvfrom( $socket, $buf, 10240, 0, $addr, $port );socket_close($socket);echo "recvfrom: [({$result}){$buf}] from [{$addr}:{$port}]";


sendto.php
<?php$socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );socket_set_option( $socket, SOL_SOCKET, SO_BROADCAST, 1 );$msg = date('Y-n-j H:i:s');$len = strlen( $msg );$result = socket_sendto( $socket, $msg, $len, 0, '255.255.255.255', 9999 );socket_close( $socket );echo "sendto: [({$result}){$msg}]";


以上两个 PHP 程序,recvfrom.php 可以用多个浏览器窗口分别发送请求,都会处在等待状态,然后再用一个浏览器窗口发送 sendto.php 的请求,前面的几个浏览器窗口就同时得到结果了。


????????????????????????????????
基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具, 分享给大家,欢迎 技术交流 :)

非常感谢
已经测试成功
现在返回去看SO_REUSEADDR的解释Reports whether local addresses can be reused. 
才恍然大悟,“是否可重复使用本地地址”
设置了这个option过后就不会再出现bind时提醒一个IP一个端口只能被建立一个连接了

刚测试发现
recvfrom.phpl里面不用加这句也成功
socket_set_option( $socket, SOL_SOCKET, SO_BROADCAST, 1 );

我认为可以删除,因为广播的页面是sendto.php,recvfrom.php只需要可重复使用本地地址和端口就行了

是这样吗?

这个我也不是很清楚。

UDP 广播包跟普通的 UDP 包一个很明显的区别就是“目标 IP 地址不同”。作为“监听 UDP 包”的 socket,从物理上讲,它肯定能“感知”到广播和非广播的 UDP 包,但它会不会“接收”广播包呢?如果你已经把这个 socket 设成“广播”型了,那肯定就没问题了,但如果不设置呢?它会不会拒收呢?

我觉得这个不好说,可能跟具体的系统实现有关吧。虽然实际使用时不写也可以,但我总觉得写上更安全。

有道理
计算一下外网的广播地址测试一下

广播地址要有子网掩码才能算啊

还得问问服务商,只有IP貌似算不了

不知道我理解得对不对,广播(broadcast)仅限于局域网内,即一个网段。要出外网的话,就是多播(multicast)了,需要路由器配合。

我做的这个其实就是对一个ip的不同端口进行广播呀

应该是可以办到的吧

如果无法办到就真的只能维护一个用户使用的端口表了

尝试了一下不行
帮我看看广播地址是不是算错了


IP 地址: 123.183.215.45
子网掩码: 255.255.255.128
默认网关: 123.183.215.1

我算出来是
123.183.215.127

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。