ホームページ  >  記事  >  バックエンド開発  >  PHPのfsockopen関数を詳しく解説

PHPのfsockopen関数を詳しく解説

WBOY
WBOYオリジナル
2016-06-23 13:18:011323ブラウズ

まず、マニュアルで fsockopen 関数がどのように定義されているかを見てみましょう。

fsockopen — ネットワーク接続または Unix ソケット接続を開きます。

リソース fsockopen ( string $hostname [, int $port = -1 [, int &$errno [, string &$errstr [, float $timeout = ini_get("default_socket_timeout") ]]]]

fsockopen を使用するこのメソッドの本質と CURL メソッドの使用は HTTP プロトコルをシミュレートすることなので、HTTP プロトコルの構築方法に焦点を当てます

注: この関数の機能を使用するには、PHP でallow_url_open をオンにする必要があります。 .ini ファイル

//打开连接通道$fp=fsockopen('www.cnblogs.com',80,$errno,$errstr,30);if(!$fp){    die('连接错误'.$errstr);}set_time_limit(0);//通道打开,模拟HTTP请求,http协议标准的换行是\r\n$http="GET / HTTP/1.1\r\n";$http.="Host: www.cnblogs.com\r\n";$http.="User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";$http.="Connection: Close\r\n\r\n";//http模拟完成,发送给服务器fwrite($fp,$http);//接受服务器的返回结果$out='';while(!feof($fp)){    $out.=fread($fp,1024);}echo $out;fclose($fp);

開発プロセス中に、ブラウザーをシミュレートしてインターフェイスにアクセスし、戻りデータを取得するという要件に遭遇することがよくあります。最も一般的に使用される方法は、fsockopen を介してインターフェイスとの接続を確立し、命令を実行し、fgets を通じて戻り値を受け取ります

しかし、PHP でシミュレートされたアクセス インターフェイスは、同じインターフェイスにアクセスするブラウザよりもはるかに遅いことがよくあります。この問題は私を長い間悩ませてきましたが、ついにその理由がわかりました。インターネット上の多くの友人が同じ問題を抱えているのを見たので、参考のために共有します

私たちはよく次のように書きます:

1 while(!feof($sHnd)) {
2 $line = fgets($sHnd, 4096);
3}
fgets は現在の 4096 (ma ybe 他の定数) ファイル記述子のバイト $sHnd . 4096 バイトに達する前に改行文字が見つかった場合は、改行文字と改行文字のみが返されます。 PHP ステートメントを段階的に実行してみると、前の fget が非常に速く、最も時間がかかることがわかりました。これは、場合によっては数秒続くこともあれば、10 秒以上続くこともあります。これはサーバーの KeepAlive 機能が原因であることがわかります (nginx などの他の Web サーバーにもあります)。この設定が On に設定されている場合、サーバーは完了後に TCP 接続を閉じません。ただし、fgets がコンテンツの最後の部分を取得するときに改行は見つからず、ファイルの終わりもありません。フラグ (feof()) があるため、fgets はコンテンツを取得した後も待機し続け、改行文字または他のコンテンツが 4096 文字に達することを期待します。そのため、サーバーと PHP はお互いを待ちながら疲弊していました。しばらくすると、サーバー接続の数は貴重なので、数秒間接続にアクティビティがない場合、接続は閉じられます (Apache は KeepAliveTimeout オプションを使用して接続を設定します)。通常、この値は 5 ~ 15 です。サーバーが接続を閉じると、PHP 側の fgets がコンテンツの最後のバッチを返し、インターフェイスにアクセスするプロセスが終了します。

遅さの理由が理解できれば、解決策がわかります。

サーバーから返された HTTP ヘッダーには、コンテンツの長さ属性が含まれており、受け入れられたコンテンツの長さがそれと等しい場合、インターフェイスのコンテンツが次のようになっていると結論付けることができます。取得済みですので、もう待つ必要はありません。具体的な方法は、コンテンツが残りの合計長 (min(4096,$leftlength)) を超えないたびに実行されます。残りの合計長が 0 になった場合、while(feof($xxxxx)) ループから抜けます。

このような修正の後、PHP のソケットを介したインターフェイスへのアクセスが遅いという問題は基本的に解決されましたが、速度の最適化を続けるという考えはまだ KeepAlive にあります。

インターフェースへのアクセスにかかる時間のかなりの部分が接続の確立に費やされることは誰もが知っていますが、インターフェースを頻繁に呼び出す必要がある場合には、最適化の余地がまだたくさんあります。サーバーが接続を維持しているので、PHPも接続を保存していれば、接続を確立する必要はないということでしょうか?答えは「はい」です。初めてインターフェイスにアクセスするときは、pfsockopen (pfsockopen と fsockopen の唯一の違いは、長い接続を確立することです) 関数を使用してサーバーとの接続を確立し、インターフェイスを閉じ (fclose) しないでください。アクセスが完了したら、この接続を直接使用してください。具体的にはコード内で次のようになります。まず接続があるかどうかを確認し、接続がある場合は引き続き使用し、ない場合は pfsockopen 接続を確立します。

さらに、インターフェイスによって返されるコンテンツが比較的短い場合 (たとえば、50 文字未満)、HTTP リクエスト ヘッダーの Accept-Encoding の gzip を削除するなど、最適化の余地がまだあります。その機能は、サーバーが gzip をサポートしている場合、圧縮されたコンテンツを受け入れることができることをサーバーに通知し、ブラウザはコンテンツを取得した後に解凍して表示します。ただし、コンテンツが短すぎる場合は、圧縮と解凍の時間を考慮すると、圧縮後のボリュームが増加し、損失が大きくなります。

上記の手順の後、アクセス インターフェイスの速度はブラウザの速度と同じになり、理論的には少し速くなります。

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