以下程序使用的是 windows 版,我正在測(cè)試 linux 版。
今天寫了一個(gè)程序,程序要求客戶端執(zhí)行服務(wù)端的shell,有的是常規(guī)的shell,有的是shell監(jiān)聽的任務(wù)。
我把兩個(gè)任務(wù)作為如下示例:
ping www.baidu.com
ping www.sina.com -t
baidu作為一個(gè)短期的shell命令,sina作為一個(gè)長(zhǎng)期監(jiān)視的shell命令。
在執(zhí)行中發(fā)現(xiàn):
1.如果瀏覽器執(zhí)行 sina 中,瀏覽器關(guān)閉了,那么服務(wù)端仍然在執(zhí)行,不會(huì)關(guān)閉當(dāng)前任務(wù);
如果 baidu 未執(zhí)行完畢時(shí),執(zhí)行了 sina,那么瀏覽器會(huì)在 baidu 執(zhí)行完畢時(shí)執(zhí)行 sina
如果先執(zhí)行 sina,然后再執(zhí)行 baidu,那么返回的消息一直屬于 sina,baidu 沒有返回
$worker->onMessage = function ($connection, $data) {
if (($connection->handle = popen($data, 'r'))) {
$connection->send('----- Task Start -----');
while (!feof($connection->handle)) {
$str = fread($connection->handle, 1024);
echo $str, "\n";
$connection->send($str);
}
$connection->send('----- Task End -----');
$connection->close();
}
};
$worker->onClose = function ($connection) {
fclose($connection->handle);
};
前端代碼:
<script>
function execWebSocket(task){
var ws = new WebSocket("ws://127.0.0.1:2345");
ws.onopen = function() {
console.log("----- WebSocket Start -----");
ws.send(task);
};
ws.onmessage = function(msg) {
console.log(msg.data);
};
ws.onclose = function() {
console.log("----- WebSocket End -----");
};
return ws;
}
//execWebSocket("ping www.baidu.com");
//execWebSocket("ping www.sina.com -t");
</script>
這里的前端我采用執(zhí)行一個(gè)shell,打開關(guān)閉一次鏈接的模式,這是使用所有的命令始終使用一個(gè) WebSocket 對(duì)象好,還是像我這樣,一個(gè)shell創(chuàng)建一次WebSocket好。
希望大神指點(diǎn)一下方向。
經(jīng)過測(cè)試 linux 可以支持多個(gè)任務(wù)并行執(zhí)行。
但是仍然存在客戶端關(guān)閉,服務(wù)端仍在執(zhí)行的情況。
執(zhí)行ping sina時(shí),while (!feof($connection->handle))一直成立的,所以程序一直在while里死循環(huán),導(dǎo)致workerman無法得到程序控制權(quán),即使客戶端斷開鏈接,workerman無法運(yùn)行到onClose。
假如我一臺(tái)服務(wù)器開了 10 個(gè)進(jìn)程,有20個(gè)客戶,每個(gè)客戶執(zhí)行一個(gè) sina (監(jiān)視任務(wù)),那么是不是我只有10個(gè)客戶能執(zhí)行成功 sina (監(jiān)視任務(wù)),其他的客戶都會(huì)在等待狀態(tài),同時(shí)所有客戶的baidu (短耗時(shí))任務(wù)也沒法執(zhí)行
假如我一臺(tái)服務(wù)器開了 10 個(gè)進(jìn)程,有20個(gè)客戶,每個(gè)客戶執(zhí)行一個(gè) sina (監(jiān)視任務(wù)),那么是不是我只有10個(gè)客戶能執(zhí)行成功 sina (監(jiān)視任務(wù)),其他的客戶都會(huì)在等待狀態(tài),同時(shí)所有客戶的baidu (短耗時(shí))任務(wù)也沒法執(zhí)行
我的這個(gè)需求是需要監(jiān)視一個(gè)目錄的文件變化然后復(fù)制到其他目錄中去,同時(shí)還有一個(gè)直接復(fù)制的命令 (類似于這樣),請(qǐng)問有什么建議嗎?假如有20個(gè)客戶監(jiān)視20個(gè)目錄的情況下 (當(dāng)然不是php監(jiān)視,而是一個(gè)其他 shell 程序)。
經(jīng)過測(cè)試,客戶的每個(gè)短耗時(shí)執(zhí)行時(shí)常(shell)需要5秒,長(zhǎng)監(jiān)視任務(wù)(shell)為一直執(zhí)行,不過只有文件改變觸發(fā)才會(huì)返回?cái)?shù)據(jù),有一臺(tái) 32 線程,64G內(nèi)存的服務(wù)器 (局域網(wǎng)),如果公司 100 個(gè)員工的話,這臺(tái)服務(wù)器是否可以支撐,同時(shí)對(duì)代碼上您有什么優(yōu)化建議嗎?
你可以看下這個(gè)demo
http://wtbis.cn/workerman-vmstat
關(guān)鍵代碼如下
// 進(jìn)程啟動(dòng)時(shí),開啟一個(gè)vmstat進(jìn)程,并廣播vmstat進(jìn)程的輸出給所有瀏覽器客戶端
$worker->onWorkerStart = function($worker)
{
// 把進(jìn)程句柄存儲(chǔ)起來,在進(jìn)程關(guān)閉的時(shí)候關(guān)閉句柄
$worker->process_handle = popen('vmstat 1', 'r');
if($worker->process_handle)
{
$process_connection = new TcpConnection($worker->process_handle);
$process_connection->onMessage = function($process_connection, $data)use($worker)
{
foreach($worker->connections as $connection)
{
$connection->send($data);
}
};
}
else
{
echo "vmstat 1 fail\n";
}
};
另外php也可以用inotify擴(kuò)展監(jiān)聽操作系統(tǒng)磁盤目錄文件訪問修改
參考 https://github.com/walkor/workerman-filemonitor-inotify
以上都是利用異步IO做的,支撐幾萬客戶端都沒事
文件的修改只是舉個(gè)例子,監(jiān)視任務(wù)是由外殼程序(shell)決定的 (改動(dòng)后的處理也是由外殼程序自動(dòng)處理的,否則又?jǐn)?shù)據(jù)一致性的問題),公司的需求也是奇葩;我看得的改改需求;如果 100 個(gè)目錄 (員工),每個(gè)員工 1K 個(gè)文件;員工上班時(shí)基本上文件都在改動(dòng)狀態(tài),這個(gè)需求也有點(diǎn)大;看來必要把監(jiān)視任務(wù)去掉,只執(zhí)行那個(gè)手動(dòng)耗時(shí) 5s 的任務(wù)了