php異步:在php中使用fsockopen curl實(shí)現(xiàn)類似異步處理的功能方法
PHP從主流來(lái)看,是一門面向過(guò)程的語(yǔ)言,它的最大缺點(diǎn)就是無(wú)法實(shí)現(xiàn)多線程管理,其程序的執(zhí)行都是從頭到尾,按照邏輯一路執(zhí)行下來(lái),不可能出現(xiàn)分支,這一點(diǎn)是限制php在主流程序語(yǔ)言中往更高級(jí)的語(yǔ)言發(fā)展的原因之一。
在PHP中我們有的時(shí)候其實(shí)希望在執(zhí)行某項(xiàng)操作的時(shí)候,同時(shí)去執(zhí)行另外一項(xiàng)操作,舉一個(gè)場(chǎng)景:在用戶搶票的時(shí)候,你并不希望用戶排隊(duì)去連接數(shù)據(jù)庫(kù)進(jìn)行查詢、判斷、插入,完成之后再返回用戶結(jié)果。其實(shí)我們并不需要用戶等那么久的時(shí)間,用戶提交之后,直接告訴他已經(jīng)搶票成功了就可以了,至于各種操作,交給后臺(tái)去處理就好。當(dāng)然,這種情況我們現(xiàn)在都用消息列表來(lái)處理,把每一個(gè)用戶提交的請(qǐng)求存在一個(gè)消息列隊(duì)中,告訴用戶已經(jīng)搞定了,用戶愉快的關(guān)掉頁(yè)面之后,實(shí)際上后臺(tái)還在一個(gè)一個(gè)從消息列隊(duì)中取出請(qǐng)求進(jìn)行操作。我們這篇文章則是通過(guò)一種異類的手法,實(shí)現(xiàn)操作在后臺(tái)運(yùn)行,無(wú)需用戶等待。
首先,我們要?jiǎng)?chuàng)建一個(gè)請(qǐng)求入口:
<?php 提交的數(shù)據(jù) 提交給后臺(tái) 告訴用戶已經(jīng)搞定了
其次,我們需要一個(gè)后臺(tái)處理程序,用戶是否在線并不影響它的運(yùn)行:
<?php ignore_user_abort(true); set_time_limit(0); 過(guò)來(lái)的數(shù)據(jù) 數(shù)據(jù)處理
現(xiàn)在的問(wèn)題是,在第一段代碼中,如何“提交給后臺(tái)”?我們通過(guò)一種非阻塞式的請(qǐng)求來(lái)實(shí)現(xiàn)這個(gè)功能。也就是創(chuàng)建一個(gè)可以被訪問(wèn)的url,在這個(gè)url運(yùn)行第二段程序,通過(guò)一個(gè)請(qǐng)求來(lái)請(qǐng)求這個(gè)url,從而激活第二段程序自動(dòng)運(yùn)行。
接下來(lái)我們直接看代碼:
// 遠(yuǎn)程請(qǐng)求(不獲取內(nèi)容)函數(shù) function _sock($url) { $host = parse_url($url,PHP_URL_HOST); $port = parse_url($url,PHP_URL_PORT); $port = $port ? $port : 80; $scheme = parse_url($url,PHP_URL_SCHEME); $path = parse_url($url,PHP_URL_PATH); $query = parse_url($url,PHP_URL_QUERY); if($query) $path .= '?'.$query; if($scheme == 'https') { $host = 'ssl://'.$host; } $fp = fsockopen($host,$port,$error_code,$error_msg,1); if(!$fp) { return array('error_code' => $error_code,'error_msg' => $error_msg); } else { stream_set_blocking($fp,true);//開啟了手冊(cè)上說(shuō)的非阻塞模式 stream_set_timeout($fp,1);//設(shè)置超時(shí) $header = "GET $path HTTP/1.1\r\n"; $header.="Host: $host\r\n"; $header.="Connection: close\r\n\r\n";//長(zhǎng)連接關(guān)閉 fwrite($fp, $header); usleep(1000); // 這一句也是關(guān)鍵,如果沒(méi)有這延時(shí),可能在nginx服務(wù)器上就無(wú)法執(zhí)行成功 fclose($fp); return array('error_code' => 0); } }
我們創(chuàng)建了一個(gè)基于fsockopen的函數(shù),這個(gè)函數(shù)中利用fsockopen去訪問(wèn)url,但是在訪問(wèn)時(shí),并不要求獲取url顯示的內(nèi)容,而是僅僅發(fā)出訪問(wèn)請(qǐng)求,請(qǐng)求到達(dá)后馬上關(guān)閉這個(gè)訪問(wèn)。這樣做的好處就是無(wú)需再等待被訪問(wèn)的url是否返回了可靠的信息,節(jié)約了時(shí)間,這段代碼的執(zhí)行時(shí)間在0.1-0.2秒之間,對(duì)于普通訪客而言,幾乎察覺(jué)不到。因此,在使用時(shí),僅需要調(diào)用這個(gè)函數(shù)和對(duì)應(yīng)的url即可。不過(guò),這里并沒(méi)有提供數(shù)據(jù)傳輸?shù)牟糠?,如何傳輸?shù)據(jù),其實(shí)只需要在$header中增加post的內(nèi)容即可。
除了fsockopen,curl其實(shí)也可以實(shí)現(xiàn)這樣的效果,有些主機(jī)上并不支持fsockopen,我們就可以使用curl來(lái)實(shí)現(xiàn)。
function _curl($url) { $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_TIMEOUT,1); $result = curl_exec($ch); curl_close($ch); return $result; }
這段代碼的關(guān)鍵是提供了一個(gè)Timeout,僅1秒鐘,也就是說(shuō)curl發(fā)出請(qǐng)求,無(wú)論是否接收到返回的內(nèi)容,1秒鐘之后都會(huì)關(guān)閉該訪問(wèn),因此這個(gè)函數(shù)的執(zhí)行數(shù)據(jù)為1.0-1.1秒之間。但對(duì)于用戶來(lái)說(shuō),如果是一個(gè)需要進(jìn)行數(shù)據(jù)處理的應(yīng)用,1秒中的等待幾乎是被忽略的,如果你希望用一段更簡(jiǎn)單和容易被理解的代碼,可以選擇curl來(lái)實(shí)現(xiàn)。
以上這篇php異步:在php中使用fsockopen curl實(shí)現(xiàn)類似異步處理的功能方法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
php實(shí)現(xiàn)網(wǎng)頁(yè)緩存的工具類分享
本文給大家分享的是php實(shí)現(xiàn)網(wǎng)頁(yè)緩存的工具類的代碼及使用方法,非常的實(shí)用,有需要的小伙伴可以參考下。2015-07-07php使用ZipArchive函數(shù)實(shí)現(xiàn)文件的壓縮與解壓縮
這篇文章主要介紹了php使用ZipArchive函數(shù)實(shí)現(xiàn)文件的壓縮與解壓縮,需要的朋友可以參考下2015-10-10PHP之生成GIF動(dòng)畫的實(shí)現(xiàn)方法
本篇文章是對(duì)PHP生成GIF動(dòng)畫的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06php中3種方法統(tǒng)計(jì)字符串中每種字符的個(gè)數(shù)并排序
3種方法,統(tǒng)計(jì)字符串中每種字符的個(gè)數(shù)并排序,多種解法喲~ str_split()函數(shù)很重要2012-08-08PHP獲取某個(gè)月最大天數(shù)(最后一天)的方法
這篇文章主要介紹了PHP獲取某個(gè)月最大天數(shù)(最后一天)的方法,涉及php流程控制及數(shù)學(xué)運(yùn)算的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07