
php はプログラムを実行しますが、数ミリ秒で完了する場合もあれば、長時間かかる場合もあります。
たとえば、ユーザーが注文を行う場合、電子メール、テキスト メッセージ、プッシュ通知などを送信するために一部のサードパーティ サービスが呼び出される場合、フロントエンドは待たされる可能性があります。
これらの時間のかかるスクリプトは、実行される限り、戻り結果を気にしないことがあります。このとき、非同期で実行する必要があります。
ご存知のとおり、PHP はマルチスレッドを直接サポートしていません。妥協した方法でそれを行うこともできます。ここで重要なのは fsockopen
です。
fsockopen を通じてリクエストを送信し、返された結果を無視すると、プログラムはすぐに戻ることができます。
サンプル コード:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $fp = fsockopen ( "www.example.com" , 80, $errno , $errstr , 30);
if (! $fp ) {
echo "$errstr ($errno)<br />\n" ;
} else {
$out = "GET /backend.php HTTP/1.1\r\n" ;
$out .= "Host: www.example.com\r\n" ;
$out .= "Connection: Close\r\n\r\n" ;
fwrite( $fp , $out );
fclose( $fp );
}
|
ログイン後にコピー
ヘッダー情報を手動で入力する必要があることに注意してください。コメントセクションを開くと、リクエストの戻り結果が表示されますが、プログラムは戻り結果を待って終了するため、今回は再び同期になります。
実際にテストしてみたところ、実行結果を無視しなければデバッグ時に毎回sockリクエストは正常に送信されるのですが、実行結果を無視するとsockリクエストが送信されないことが多いことが分かりました。成功しました。 nginx ログを確認すると、ステータス コード 499 のリクエストが多数見つかります。
後で理由がわかりました。
fwrite
は fclose
の直後に実行され、nginx は直接 499 を返します。リクエストは処理のために php に転送されます。
クライアントがアクティブ ポートを介して接続をリクエストした場合、NGINX はリクエストを上流のサービス (FastCGI PHP プロセス) にプロキシしません。このとき、リクエストはアクセス ログに 499 として記録されます。
解決策:
1) nginx.conf に構成を追加します。
1 2 | # 忽略客户端中断
fastcgi_ignore_client_abort on;
|
ログイン後にコピー
2) fwrite の後に usleep を使用します。関数は 20 ミリ秒スリープします:
その後のテストでは障害は見つかりませんでした。
完全なコードを添付します:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | <?php
class FsockService {
public static function post( $url , $param ){
$host = parse_url ( $url , PHP_URL_HOST);
$port = 80;
$errno = '';
$errstr = '';
$timeout = 30;
$data = http_build_query( $param );
$fp = fsockopen ( $host , $port , $errno , $errstr , $timeout );
if (! $fp ){
return false;
}
$out = "POST ${url} HTTP/1.1\r\n" ;
$out .= "Host:${host}\r\n" ;
$out .= "Content-type:application/x-www-form-urlencoded\r\n" ;
$out .= "Content-length:" . strlen ( $data ). "\r\n" ;
$out .= "Connection:close\r\n\r\n" ;
$out .= "${data}" ;
fwrite( $fp , $out );
if (false){
$ret = '';
while (! feof ( $fp )) {
$ret .= fgets ( $fp , 128);
}
}
usleep(20000);
fclose( $fp );
}
public static function get( $url , $param ){
$host = parse_url ( $url , PHP_URL_HOST);
$port = 80;
$errno = '';
$errstr = '';
$timeout = 30;
$url = $url .'?'.http_build_query( $param );
$fp = fsockopen ( $host , $port , $errno , $errstr , $timeout );
if (! $fp ){
return false;
}
$out = "GET ${url} HTTP/1.1\r\n" ;
$out .= "Host:${host}\r\n" ;
$out .= "Connection:close\r\n\r\n" ;
fwrite( $fp , $out );
if (false){
$ret = '';
while (! feof ( $fp )) {
$ret .= fgets ( $fp , 128);
}
}
usleep(20000);
fclose( $fp );
}
}
?>
|
ログイン後にコピー
関連する php の知識については、php チュートリアル をご覧ください。
以上がPHP で fsockopen を使用して非同期リクエストを実装する (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。