同步请求和异步请求

对于一个 WEB 程序员来说,如果他对同步执行模式与异步执行模式不了解, 他往往会在对服务器发出一个操作语句(查询或读取一条记录等操作)后,立该引用服务器返回的执行结果,或者对该结果进行下一步操作,这是很危险的。对于一个简单的过程来说,这样不会存在什么大问题,但如果涉及到一个很复杂的操作过程,比如客户机上的后续语句是在该操作语句发 出后接着执行的,但由于各种原因,服务器不一定能执行完该操作语句,并在后续语句执行前将结果返回客户机。那么后续语句在引用前一操作语句的执行结果时,往往会因为该执行结果并不存在而引用了错误的值,进而造成系统错误或死锁,所以在实际应用中应根据具体情况慎重选择相应的请求模式。

首先我们来学习一下http请求中同步请求与异步请求的定义:

同步请求是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。 

异步请求是指:发送方发出数据后,不等接收方发回响应,继续接着发送下一个数据包的通讯方式。

虽然使用异步执行模式相对于同步执行模式时比较麻烦点,但异步模式可以实现多任务并行执行,使用户体验度以及程序执行效率都会有大大的提高。那么在应用程序开发中是选择同步模式还是异步模式,要根据具体的情况来进行判断。当查询或对数据库的修改相对简单时,选择同步执行模式就已经足够了,它能够在几秒或更少的时间内返回结果数据。另外,在应用程序获得结果集前不能继续执行时,根本不必要使用异步执行模式。在复杂查询情况下,特别是复杂的多个表之间的 UPDATE 或 DELETE 操作时,可能需要很长的时间才能完成,这个时候采用异步执行模式最好,让用户可以同时对程序的其他部分进行操作




使用JavaScript/Ajax可轻松实现异步HTTP请求,本文介绍使用PHP进行异 步HTTP请求。所谓异步HTTP请求是指:HTTP协议基于TCP且是基于状态的,client和server建立 连接后发送请求需要等到server处理结束并返回后才可以断开连接。某些情况下,client端只需要发出自己的请求即可,不需要知道 server端的响应,这个时候即需要实现client端发出异步HTTP请求。另外,在长耗时应用中(请求的server端任务比较 耗时,超过HTTP timeout时间甚至更长),也可以考虑使用异步HTTP请求出发该任务。关于长耗时应用也可以参考该文

方法1:使用curl的CURLOPT_TIMEOUTCURLOPT_TIMEOUT_MS

设置CURLOPT_TIMEOUT为最小值1,client端在等待1秒之后即返回。

    $url = "http://www.yoursite.com/background-script.php";
    $ref_url = "http://www.yoursite.com";
    $data = array(
        "key1" => "value1",
        "key2" => "value2",
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_USERAGENT, $agent);
    curl_setopt($ch, CURLOPT_REFERER, $ref_url);

    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);        

    curl_setopt($ch, CURLOPT_TIMEOUT, 1);

    curl_exec($ch);
    curl_close($ch);
如果是cURL 7.16.2 or higher and PHP 5.2.3 or above,可以设置Timeout时间为1  ms,实现立即返回,修改如上的curl_setopt($ch, CURLOPT_TIMEOUT, 1);为curl_setopt($ch,  CURLOPT_TIMEOUT_MS, 1);。
方法2:使用socket修改HTTP header
使用socket连接到server上,发送raw HTTP header(注意设置Connection: Close), 完成之后立即关闭socket不等待server做出响应再返回。
GET例子
需要请求的server url为http://example.com/Default.aspx,接受的参数为action=start,method 为GET,需要携带的cookies为ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah。(这 些信息都可以使用HttpWatch分析得到)。
例如HttpWatch的分析的client端的HTTP请求为:
    GET /Default.aspx?action=start HTTP/1.1
    Accept-Language: zh-cn
    User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)
    Accept-Encoding: gzip, deflate
    Host: example.com
    Connection: Keep-Alive
    Cookie: ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah
    
    修改为异步HTTP请求:
    <?php

    $host = "example.com";
    $path = "/Default.aspx?action=start";
    $cookie = "ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah";

    $start = microtime(true);

    $fp = fsockopen($host, 80, $errno, $errstr, 30);
    if (!$fp) {
       print "$errstr ($errno)<br />\n";
       exit;
    }
    $out = "GET ".$path." HTTP/1.1\r\n";
    $out .= "Host: ".$host."\r\n";          //需要注意Host不能包括`http://`,仅可以使用`example.com`
    $out .= "Connection: Close\r\n";
    $out .= "Cookie: ".$cookie."\r\n\r\n";

    fwrite($fp, $out);  //将请求写入socket

    /*
    //也可以选择获取server端的响应
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }
    */

    //如果不等待server端响应直接关闭socket即可
    fclose($fp);

    $cost = microtime(true) - $start;
    print "\n".$cost."\n";
    exit;
POST例子

需要请求的server url为http://example.com/Login.aspx,接受的参数为username=my-username&password=my-password,method 为POST,需要携带的cookies为ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah。(这 些信息都可以使用HttpWatch分析得到)。

例如HttpWatch的分析的client端的HTTP请求为:

    POST /Login.aspx HTTP/1.1
    Accept-Language: zh-cn
    User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)
    Content-Type: application/x-www-form-urlencoded
    Accept-Encoding: gzip, deflate
    Host: example.com
    Connection: Keep-Alive
    Cache-Control: no-cache
    Cookie: ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah

    username=my-username&password=my-password

修改为异步HTTP请求:

    <?php

    $host = "example.com";
    $path = "/Login.aspx";
    $cookie = "ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah";
    $params = "username=my-username&password=my-password";

    $start = microtime(true);

    $fp = fsockopen($host, 80, $errno, $errstr, 30);
    if (!$fp) {
       print "$errstr ($errno)<br />\n";
       exit;
$out = "POST ".$path." HTTP/1.1\r\n";
    $out .= "Host: ".$host."\r\n";
    $out .= "Connection: Close\r\n";
    $out .= "Cookie: ".$cookie."\r\n\r\n";
    $out .= $params;

    fwrite($fp, $out);  

    /*
    //也可以选择获取server端的响应
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }
    */

    //如果不等待server端响应直接关闭socket即可
    fclose($fp);

    $cost = microtime(true) - $start;
    print "\n".$cost."\n";
    exit;

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值