異步tcp我認(rèn)為的是,tcp請求會做到異步化,tcp發(fā)起請求后,程序自己可以處理其他業(yè)務(wù),tcp有結(jié)果了就執(zhí)行回調(diào)函數(shù),但是通過我的實(shí)驗(yàn)并不是。不知道是我代碼有問題還是怎么回事,求解答。
$task = new Worker();
$task->onWorkerStart = function ($task) {
$connection_to_baidu = new AsyncTcpConnection('tcp://xx.xx.xx.xxx:80');
$connection_to_baidu->onConnect = function ($connection_to_baidu) {
echo "connect success\n";
$connection_to_baidu->send("GET /Mapi/v3/Test/test HTTP/1.1\r\nHost: xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");
};
$connection_to_baidu->onMessage = function ($connection_to_baidu, $http_buffer) {
echo $http_buffer;
};
$connection_to_baidu->onClose = function ($connection_to_baidu) {
echo "connection closed\n";
};
$connection_to_baidu->onError = function ($connection_to_baidu, $code, $msg) {
echo "Error code:$code msg:$msg\n";
};
$connection_to_baidu->connect(); //通過抓包分析,此處會與服務(wù)器三次握手
//模擬處理正常其他業(yè)務(wù) 此處業(yè)務(wù)耗時大于3秒
for ($i = 0; $i < 30000; $i++) {
echo $i . PHP_EOL;
file_get_contents('workerman.log'); //為了防止此處,一直占用cpu資源,做io操作,讓cpu有機(jī)會去執(zhí)行回調(diào)函數(shù)
}
//此時會打印connect success, 抓包此處才會發(fā)起http請求 發(fā)送$connection_to_baidu->send("GET /Mapi/v3/Test/test HTTP/1.1\r\nHost: xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");
//因?yàn)榻涌趕leep睡眠了三秒返回,此處會有大概三秒等待,然后會執(zhí)行onMessage回調(diào)函數(shù) 打印結(jié)果到控制臺
};
// 運(yùn)行worker
Worker::runAll();
workerman運(yùn)行可以認(rèn)為分為2個狀態(tài),一個是執(zhí)行業(yè)務(wù)狀態(tài),一個是workerman內(nèi)核態(tài)狀態(tài),2個狀態(tài)是串行的,并不會并發(fā)執(zhí)行。
執(zhí)行業(yè)務(wù)狀態(tài)也就是進(jìn)程在運(yùn)行業(yè)務(wù)代碼時的狀態(tài),這時候workerman內(nèi)核沒有控制權(quán);
workerman內(nèi)核狀態(tài)是業(yè)務(wù)執(zhí)行完畢后交出控制權(quán)后workerman內(nèi)核運(yùn)行的狀態(tài);
workerman內(nèi)核狀態(tài)實(shí)際上就是一個event-loop,會監(jiān)聽操作系統(tǒng)發(fā)送給workerman的連接事件、連接可讀可寫、關(guān)閉事件,并觸發(fā)onConnect、onMessage、onClose等。只有在workerman內(nèi)核態(tài)才能接收到這些事件,在執(zhí)行業(yè)務(wù)狀態(tài)無法接收并觸發(fā)這些事件。
這就很好的解釋了為什么上面的代碼為什么在業(yè)務(wù)代碼執(zhí)行完畢后才真正發(fā)出了請求。
如果你想要在執(zhí)行業(yè)務(wù)邏輯的時候通知其它進(jìn)程同步處理業(yè)務(wù)邏輯,你應(yīng)該用同步的方式發(fā)起連接和數(shù)據(jù),然后在需要數(shù)據(jù)的時候讀取它。代碼類似這樣:
$task = new Worker();
$task->onWorkerStart = function ($task) {
$socket = stream_socket_client('tcp://xx.xx.xx.xxx:80');
fwrite($socket, "GET /Mapi/v3/Test/test HTTP/1.1\r\nHost: xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");
//模擬處理正常其他業(yè)務(wù) 此處業(yè)務(wù)耗時大于3秒
for ($i = 0; $i < 30000; $i++) {
echo $i . PHP_EOL;
file_get_contents('workerman.log'); //為了防止此處,一直占用cpu資源,做io操作,讓cpu有機(jī)會去執(zhí)行回調(diào)函數(shù)
}
echo fread($socket, 8192);
};
// 運(yùn)行worker
Worker::runAll();
這樣在你處理業(yè)務(wù)的時候,遠(yuǎn)處的進(jìn)程也在處理。當(dāng)你需要獲得結(jié)果的時候,用fread阻塞等待獲得結(jié)果即可。
如果你想同步的方式發(fā)起請求,異步的方式獲得結(jié)果,可以用下面的方法。
use Workerman\Connection\TcpConnection;
$task = new Worker();
$task->onWorkerStart = function ($task) {
$socket = stream_socket_client('tcp://xx.xx.xx.xxx:80');
fwrite($socket, "GET /Mapi/v3/Test/test HTTP/1.1\r\nHost:xx.xx.xx.xxx\r\nConnection: keep-alive\r\n\r\n");
$connection = new TcpConnection($socket);
$connection->onMessage = function($connection, $http_buffer){
echo $http_buffer;
$connection->close(); // 連接不用了要記得關(guān)閉
}
//模擬處理正常其他業(yè)務(wù) 此處業(yè)務(wù)耗時大于3秒
for ($i = 0; $i < 30000; $i++) {
echo $i . PHP_EOL;
file_get_contents('workerman.log'); //為了防止此處,一直占用cpu資源,做io操作,讓cpu有機(jī)會去執(zhí)行回調(diào)函數(shù)
}
};
// 運(yùn)行worker
Worker::runAll();
workerman-json-rpc 的異步客戶端就是你這種方式實(shí)現(xiàn)的異步。我以前認(rèn)為AsyncTcpConnection默認(rèn)就實(shí)現(xiàn)了完全異步化。 感謝作者在百忙之中回答。