>  기사  >  백엔드 개발  >  PHP에서 fsockopen을 사용하여 비동기 요청 구현(코드 예)

PHP에서 fsockopen을 사용하여 비동기 요청 구현(코드 예)

藏色散人
藏色散人앞으로
2020-01-22 17:44:072734검색

PHP에서 fsockopen을 사용하여 비동기 요청 구현(코드 예)

php는 프로그램을 실행하는데, 이 작업은 몇 밀리초 안에 완료되거나 오랜 시간이 걸릴 수 있습니다.

예를 들어 사용자가 주문을 하는 경우 일부 타사 서비스를 호출하여 이메일, 문자 메시지, 푸시 알림 등을 보내는 경우 프런트 엔드가 계속 대기할 수 있습니다.

때때로 우리는 시간이 많이 걸리는 스크립트가 실행되는 한 이러한 스크립트의 반환 결과에 신경 쓰지 않습니다. 이때 비동기적으로 실행해야 합니다.

우리 모두 알고 있듯이 PHP는 멀티스레딩을 직접 지원하지 않습니다. 우리는 타협적인 방식으로 이를 할 수 있습니다. 여기서 가장 중요한 것은 fsockopen입니다. fsockopen

通过fsockopen发送请求并忽略返回结果,程序可以马上返回。

示例代码:

$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);
    /*忽略执行结果
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }*/
    fclose($fp);
}

需要注意的是我们需要手动拼出header头信息。通过打开注释部分,可以查看请求返回结果,但这时候又变成同步的了,因为程序会等待返回结果才结束。

实际测试的时候发现,不忽略执行结果,调试的时候每次都会成功发送sock请求;但忽略执行结果,经常看到没有成功发送sock请求。查看nginx日志,发现很多状态码为499的请求。

后来找到了原因:

fwrite之后马上执行fclose

fsockopen을 통해 요청을 보내고 반환 결과를 무시하면 프로그램이 즉시 반환될 수 있습니다.

샘플 코드:

# 忽略客户端中断
fastcgi_ignore_client_abort on;

헤더 정보를 수동으로 입력해야 한다는 점에 유의하세요. 주석 섹션을 열면 요청 반환 결과를 볼 수 있지만 이번에는 프로그램이 종료되기 전에 반환 결과를 기다리기 때문에 다시 동기가 됩니다.

실제 테스트에서 실행 결과를 무시하지 않으면 디버깅할 때마다 sock 요청이 성공적으로 전송되지만 실행 결과를 무시하면 sock 요청이 자주 전송되는 것으로 나타났습니다. 성공적으로 전송되지 않았습니다. nginx 로그를 확인하고 상태 코드가 499인 요청을 많이 찾으세요.

나중에 이유를 찾았습니다:

fwrite 직후에 fclose를 실행합니다. nginx 499가 직접 반환되며 요청은 처리를 위해 PHP로 전달되지 않습니다.

클라이언트가 적극적으로 연결을 요청하면 NGINX는 요청을 업스트림 서비스(FastCGI PHP 프로세스)로 프록시하지 않습니다. 이때 요청은 액세스 로그에 499로 기록됩니다.

솔루션:

1) nginx.conf 구성 추가

#🎜🎜#
usleep(20000);
#🎜🎜 # #🎜🎜#2) fwrite 후에 usleep 함수를 사용하여 20밀리초 동안 절전 모드로 전환합니다. #🎜🎜##🎜🎜#
<?php
/**
 * 工具类
 * */
class FsockService {
    
    public static function post($url, $param){
        $host = parse_url($url, PHP_URL_HOST);
        $port = 80;
        $errno = &#39;&#39;;
        $errstr = &#39;&#39;;
        $timeout = 30;
        $data = http_build_query($param);
        // create connect
        $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
        if(!$fp){
            return false;
        }
        // send request
        $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(APP_DEBUG === true){
        if(false){
            $ret = &#39;&#39;;
            while (!feof($fp)) {
                $ret .= fgets($fp, 128);
            }
        }
        usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
        fclose($fp);
    }
    public static function get($url, $param){
        $host = parse_url($url, PHP_URL_HOST);
        $port = 80;
        $errno = &#39;&#39;;
        $errstr = &#39;&#39;;
        $timeout = 30;
        $url = $url.&#39;?&#39;.http_build_query($param);
        // create connect
        $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
        if(!$fp){
            return false;
        }
        // send request
        $out = "GET ${url} HTTP/1.1\r\n";
        $out .= "Host:${host}\r\n";
        $out .= "Connection:close\r\n\r\n";
        fwrite($fp, $out);
        //忽略执行结果;否则等待返回结果
//        if(APP_DEBUG === true){
        if(false){
            $ret = &#39;&#39;;
            while (!feof($fp)) {
                $ret .= fgets($fp, 128);
            }
        }
        usleep(20000); //fwrite之后马上执行fclose,nginx会直接返回499
        fclose($fp);
    }
   
}
?>
#🎜🎜# 나중에 테스트 결과 오류가 발견되지 않았습니다. #🎜🎜##🎜🎜##🎜🎜#첨부된 코드는 전체 코드입니다: #🎜🎜##🎜🎜#rrreee#🎜🎜#더 많은 관련 PHP 지식을 보려면 #🎜🎜#php 튜토리얼#🎜🎜#을 방문하세요! #🎜🎜#

위 내용은 PHP에서 fsockopen을 사용하여 비동기 요청 구현(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제