前面参与一项目,逻辑处理比较多,所以采用异步处理。
因为之前采用异步处理时 Web 服务器是 Apache,而这次测试时也是,到把代码更新到服务器上时,执行死活不成功。折腾一番之后,才记起服务器上的 Web 服务器是 Nginx。试着从这个角度查找原因,找到如下这篇文章:
测试环境,从本机(Windows)访问内外一台 Linux 服务器(此服务器装的是 Nginx)。
index.php 代码:
1 2 3 | <!--?php echo 1; ?--> |
1 使用HTTP 1.1 协议请求
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 | function asyn_sendmail() { $ip = '192.168.1.45' ; $url = '/index.php' ; $fp = fsockopen ( $ip , 80, $errno , $errstr , 5); if (! $fp ) { echo "$errstr ($errno)<br>\\n" ; } $end = "\\r\\n" ; $input = "GET $url HTTP/1.1$end" ; //如果不加下面这一句,会返回一个 HTTP400 错误 //$input.="Host: $ip$end"; //如果不加下面这一句,请求会阻塞很久 //$input.="Connection: Close$end"; $input .= "$end" ; fputs ( $fp , $input ); $html = '' ; while (! feof ( $fp )) { $html .= fgets ( $fp ); } fclose( $fp ); writelog( $html ); echo $html ; } function writelog( $message ) { $path = 'log.txt' ; $handler = fopen ( $path , 'w+b' ); if ( $handler ) { $success = fwrite( $handler , $message ); fclose( $handler ); } } asyn_sendmail(); |
如果注释了 $input.="Host: $ip$end"; 这一句,则会得到一个 404 错误,log.txt 内容如下:
HTTP/1.1 400 Bad Request Server: nginx/0.8.46 Date: Fri, 30 Dec 2011 02:11:45 GMT Content-Type: text/html Content-Length: 173 Connection: close400 Bad Request
nginx/0.8.46
说明:使用 HTTP 1.1 连接,则必须加上 Host请 求表头。
如果加上了没有注释 $input.="Host: $ip$end"; 这一句 ,则请求成功,log.txt 内容如下:
HTTP/1.1 200 OK Server: nginx/0.8.46 Date: Fri, 30 Dec 2011 02:20:49 GMT Content-Type: text/html Transfer-Encoding: chunked Connection: keep-alive Vary: Accept-Encoding X-Powered-By: PHP/5.3.8 1 0 0
返回成功,但是不明白为什么服务器返回内容多了2个 0 (后来网上查询资料发现,这是因为服务器使用了 chunked 输出所致,用 Wireshark 抓包可清晰看到其细节)。如果不加 $input.="Connection: Close$end"; 这一句 ,则 HTTP 请求会阻塞很久(在这一句 fgets($fp) 阻塞)。
2 不指定 HTTP 版本
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 | <!--?php function asyn_sendmail() { $ip = '192.168.1.45' ; $url = '/servertimmer/inserttopicshow/13990/AA8AB76B-7280-578F-12F2-F423685FBD26' ; $fp = fsockopen ( $ip , 80, $errno , $errstr , 5); if (! $fp ) { echo "$errstr ($errno)<br /-->\\n" ; } $end = "\\r\\n" ; $input = "GET $url$end" ; $input .= "$end" ; fputs ( $fp , $input ); $html = '' ; while (! feof ( $fp )) { $html .= fgets ( $fp ); } fclose( $fp ); writelog( $html ); echo $html ; } function writelog( $message ) { $path = 'log.txt' ; $handler = fopen ( $path , 'w+b' ); if ( $handler ) { $success = fwrite( $handler , $message ); fclose( $handler ); } } asyn_sendmail(); ?> |
请求立刻返回,没有阻塞,返回内容如下:
1
注意:返回内容中没有http标头,且没有被阻塞。
参考上面,代码中,发送到头部信息中正是少了第一段中提到的 $input.="Connection: Close$end";,添加上,问题解决。
总结:
fsockopen 上采用 POST 方法的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $domain = "localhost" ; $url = '/tool/async-test.php' ; $param = "a=1&b=2&c=3&d=4" ; $header = "POST $url HTTP/1.1\\r\\n" ; $header .= "Host: $domain\\r\\n" ; $header .= "Content-Type:application/x-www-form-urlencoded\\r\\n" ; $header .= "Content-Length:" . strlen ( $param ) . "\\r\\n\\r\\n" ; $header .= "Connection: close\\r\\n" ; $fp = @ fsockopen ( $domain , 80, $errno , $errstr , 30); fputs ( $fp , $header . $param ); $html = '' ; while (! feof ( $fp )) { $html .= fgets ( $fp ); } echo $html ; fclose( $fp ); |
友情提示:垃圾评论一律封号...