成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Swoole源碼研究】淺析swoole中server的實(shí)現(xiàn)

rainyang / 2186人閱讀

摘要:的部分是基于以及協(xié)議的。例如父進(jìn)程向中寫入子進(jìn)程從中讀取子進(jìn)程向中寫入父進(jìn)程從中讀取。默認(rèn)使用對(duì)進(jìn)程進(jìn)行分配交給對(duì)應(yīng)的線程進(jìn)行監(jiān)聽線程收到某個(gè)進(jìn)程的數(shù)據(jù)后會(huì)進(jìn)行處理值得注意的是這個(gè)線程可能并不是發(fā)送請(qǐng)求的那個(gè)線程。

作者:施洪寶

一. 基礎(chǔ)知識(shí) 1.1 swoole

swoole是面向生產(chǎn)環(huán)境的php異步網(wǎng)絡(luò)通信引擎, php開發(fā)人員可以利用swoole開發(fā)出高性能的server服務(wù)。swoole的server部分, 內(nèi)容很多, 也涉及很多的知識(shí)點(diǎn), 本文僅對(duì)其server進(jìn)行簡單的概述, 具體的實(shí)現(xiàn)細(xì)節(jié)在后續(xù)的文章中再進(jìn)行詳細(xì)介紹。

1.2 網(wǎng)絡(luò)編程

網(wǎng)絡(luò)通信是指在一臺(tái)(或者多臺(tái))機(jī)器上啟動(dòng)一個(gè)(或者多個(gè))進(jìn)程, 監(jiān)聽一個(gè)(或者多個(gè))端口, 按照某種協(xié)議(可以是標(biāo)準(zhǔn)協(xié)議http, dns; 也可以是自行定義的協(xié)議)與客戶端交換信息。

目前的網(wǎng)絡(luò)編程多是在tcp, udp或者更上層的協(xié)議之上進(jìn)行編程。swoole的server部分是基于tcp以及udp協(xié)議的。

利用udp進(jìn)行編程較為簡單, 本文主要介紹tcp協(xié)議之上的網(wǎng)絡(luò)編程

TCP網(wǎng)絡(luò)編程主要涉及4種事件,

連接建立: 主要是指客戶端發(fā)起連接(connect)以及服務(wù)端接受連接(accept)

消息到達(dá): 服務(wù)端接受到客戶端發(fā)送的數(shù)據(jù), 該事件是TCP網(wǎng)絡(luò)編程最重要的事件, 服務(wù)端對(duì)于該類事件進(jìn)行處理時(shí), 可以采用阻塞式或者非阻塞式, 除此之外, 服務(wù)端還需要考慮分包, 應(yīng)用層緩沖區(qū)等問題

消息發(fā)送成功: 發(fā)送成功是指應(yīng)用層將數(shù)據(jù)成功發(fā)送到內(nèi)核的套接字發(fā)送緩沖區(qū)中, 并不是指客戶端成功接受數(shù)據(jù)。對(duì)于低流量的服務(wù)而言, 數(shù)據(jù)通常一次性即可發(fā)送完, 并不需要關(guān)心此類事件。如果一次性不能將全部數(shù)據(jù)發(fā)送到內(nèi)核緩沖區(qū), 則需要關(guān)心消息是否成功發(fā)送(阻塞式編程在系統(tǒng)調(diào)用(write, writev, send等)返回后即是發(fā)送成功, 非阻塞式編程則需要考慮實(shí)際寫入的數(shù)據(jù)是否與預(yù)期一致)

連接斷開: 需要考慮客戶端斷開連接(read返回0)以及服務(wù)端斷開連接(close, shutdown)

1.3 進(jìn)程間通信

進(jìn)程之間的通信有無名管道(pipe), 有名管道(fifo), 信號(hào), 信號(hào)量, 套接字, 共享內(nèi)存等方式

swoole中采用unix域套接字用于多進(jìn)程之間的通信(指swoole內(nèi)部進(jìn)程之間)

1.4 socketpair

socketpair用于創(chuàng)建一個(gè)套接字對(duì), 類似于pipe, 不同的是pipe是單向通信, 雙向通信需要?jiǎng)?chuàng)建兩次, socketpair調(diào)用一次即可實(shí)現(xiàn)雙向通信, 除此之外, 由于使用的是套接字, 還可以定義數(shù)據(jù)交換的方式

socketpair系統(tǒng)調(diào)用

int socketpair(int domain, int type, int protocol, int sv[2]);
//domain表示協(xié)議簇
//type表示類型
//protocol表示協(xié)議, SOCK_STREAM表示流協(xié)議(類似tcp), SOCK_DGRAM表示數(shù)據(jù)報(bào)協(xié)議(類似udp)
//sv用于存儲(chǔ)建立的套接字對(duì), 也就是兩個(gè)套接字文件描述符
//成功返回0, 否則返回-1, 可以從errno獲取錯(cuò)誤信息

調(diào)用成功后sv[0], sv[1]分別存儲(chǔ)一個(gè)文件描述符

向sv[0]中寫入, 可以從sv[1]中讀取

向sv[1]中寫入, 可以從sv[0]中讀取

進(jìn)程調(diào)用socketpair后, fork子進(jìn)程, 子進(jìn)程會(huì)默認(rèn)繼承sv[0], sv[1]這兩個(gè)文件描述符, 進(jìn)而可以實(shí)現(xiàn)父子進(jìn)程間通信。例如, 父進(jìn)程向sv[0]中寫入, 子進(jìn)程從sv[1]中讀取; 子進(jìn)程向sv[1]中寫入, 父進(jìn)程從sv[0]中讀取。

1.5 守護(hù)進(jìn)程(daemon)

守護(hù)進(jìn)程是一種特殊的后臺(tái)進(jìn)程, 它脫離于終端, 用于周期性的執(zhí)行某種任務(wù)

進(jìn)程組

每個(gè)進(jìn)程都屬于一個(gè)進(jìn)程組

每個(gè)進(jìn)程組都有一個(gè)進(jìn)程組號(hào), 也就是該組組長的進(jìn)程號(hào)(PID)

一個(gè)進(jìn)程只能為自己或者其子進(jìn)程設(shè)置進(jìn)程組號(hào)

會(huì)話

一個(gè)會(huì)話可以包含多個(gè)進(jìn)程組, 這些進(jìn)程組中最多只能有一個(gè)前臺(tái)進(jìn)程組(也可以沒有)

setsid可以創(chuàng)建一個(gè)新的會(huì)話, 該進(jìn)程不能是進(jìn)程組的組長。setsid調(diào)用完成后, 該進(jìn)程成為這個(gè)會(huì)話的首進(jìn)程(領(lǐng)頭進(jìn)程), 同時(shí)變成一個(gè)新的進(jìn)程組的組長, 如果該進(jìn)程之前有控制終端, 則該進(jìn)程與終端的聯(lián)系被斷開

用戶通過終端登錄或者網(wǎng)絡(luò)登錄, 會(huì)創(chuàng)建一個(gè)新的會(huì)話

一個(gè)會(huì)話最多只能有一個(gè)控制終端

創(chuàng)建守護(hù)進(jìn)程的方式

fork子進(jìn)程后, 父進(jìn)程退出, 子進(jìn)程執(zhí)行setsid即可成為守護(hù)進(jìn)程。這種方式下, 子進(jìn)程是會(huì)話的領(lǐng)頭進(jìn)程, 可以重新打開終端, 此時(shí)可以再次fork, fork產(chǎn)生的子進(jìn)程無法再打開終端。第二次fork并不是必須的, 只是為了防止子進(jìn)程再次打開終端

linux提供了daemon函數(shù)用于創(chuàng)建守護(hù)進(jìn)程

1.6 swoole tcp server示例
set(array(
    "reactor_num" => 2, //reactor thread num
    "worker_num" => 3,  //worker process num
));

//設(shè)置事件回調(diào)
$serv->on("connect", function ($serv, $fd){
    echo "Client:Connect.
";
});
$serv->on("receive", function ($serv, $fd, $reactor_id, $data) {
    $serv->send($fd, "Swoole: ".$data);
    $serv->close($fd);
});
$serv->on("close", function ($serv, $fd) {
    echo "Client: Close.
";
});

//啟動(dòng)server
$serv->start();

上述代碼在cli模式下執(zhí)行時(shí), 經(jīng)過詞法分析, 語法分析生成opcode, 進(jìn)而交由zend虛擬機(jī)執(zhí)行

zend虛擬機(jī)在執(zhí)行到$serv->start()時(shí), 啟動(dòng)swoole server

上述代碼中設(shè)置的事件回調(diào)是在worker進(jìn)程中執(zhí)行, 后文會(huì)詳細(xì)介紹swoole server模型

二. swoole server 2.1 base模式

說明

base模式采用多進(jìn)程模型, 這種模型與nginx一致, 每個(gè)進(jìn)程只有一個(gè)線程, 主進(jìn)程負(fù)責(zé)管理工作進(jìn)程, 工作進(jìn)程負(fù)責(zé)監(jiān)聽端口, 接受連接, 處理請(qǐng)求以及關(guān)閉連接

多個(gè)進(jìn)程同時(shí)監(jiān)聽端口, 會(huì)有驚群問題, 目前swoole并沒有解決

linux 內(nèi)核3.9及其后續(xù)版本提供了新的套接字參數(shù)SO_REUSEPORT, 該參數(shù)允許多個(gè)進(jìn)程綁定到同一個(gè)端口, 內(nèi)核在接受到新的連接請(qǐng)求時(shí), 會(huì)喚醒其中一個(gè)進(jìn)行處理, 內(nèi)核層面也會(huì)做負(fù)載均衡, 可以解決上述的驚群問題

base模式下, reactor_number參數(shù)并沒有作用, 因?yàn)槊總€(gè)進(jìn)程只有一個(gè)線程

如果worker進(jìn)程數(shù)設(shè)置為1, 則不會(huì)fork出worker進(jìn)程, 主進(jìn)程直接處理請(qǐng)求

啟動(dòng)過程

php代碼執(zhí)行到$serv->start()時(shí), 主進(jìn)程進(jìn)入int swServer_start(swServer *serv)函數(shù), 該函數(shù)負(fù)責(zé)啟動(dòng)server

在函數(shù)swServer_start中會(huì)調(diào)用swReactorProcess_start, 這個(gè)函數(shù)會(huì)fork出多個(gè)worker進(jìn)程

主進(jìn)程和worker進(jìn)程各自進(jìn)入自己的事件循環(huán), 處理各類事件

2.2 process模式

說明

這種模式為多進(jìn)程多線程, 有主進(jìn)程, manager進(jìn)程, worker進(jìn)程, task_worker進(jìn)程

主進(jìn)程下有多個(gè)線程, 主線程負(fù)責(zé)接受連接, 之后交給react線程處理請(qǐng)求。 react線程負(fù)責(zé)接收數(shù)據(jù)包, 并將數(shù)據(jù)轉(zhuǎn)發(fā)給worker進(jìn)程進(jìn)行處理, 之后處理worker進(jìn)程返回的數(shù)據(jù)

manager進(jìn)程, 該進(jìn)程為單線程, 主要負(fù)責(zé)管理worker進(jìn)程, 類似于nginx中的主進(jìn)程, 當(dāng)worker進(jìn)程異常退出時(shí), manager進(jìn)程負(fù)責(zé)重新fork出一個(gè)worker進(jìn)程

worker進(jìn)程, 該進(jìn)程為單線程, 負(fù)責(zé)具體處理請(qǐng)求

task_worker進(jìn)程, 用于處理比較耗時(shí)的任務(wù), 默認(rèn)不開啟

worker進(jìn)程與主進(jìn)程中的react線程使用域套接字進(jìn)行通信, worker進(jìn)程之間不進(jìn)行通信

啟動(dòng)過程

swoole server啟動(dòng)入口: swServer_start函數(shù),

//php 代碼中$serv->start(); 會(huì)調(diào)用函數(shù), 進(jìn)行server start
int swServer_start(swServer *serv);

// 該函數(shù)首先進(jìn)行必要的參數(shù)檢查
static int swServer_start_check(swServer *serv);
// 其中有,
if (serv->worker_num < serv->reactor_num)
{
    serv->reactor_num = serv->worker_num;
}//也就是說reactor_num <= worker_num

//之后執(zhí)行factory start, 也就是swFactoryProcess_start函數(shù), 該函數(shù)會(huì)fork出manager進(jìn)程, manager進(jìn)程進(jìn)而fork出worker進(jìn)程以及task_worker進(jìn)程
if (factory->start(factory) < 0)
{
    return SW_ERR;
}

//然后主進(jìn)程的主線程生成reactor線程
if (serv->factory_mode == SW_MODE_BASE)
{
    ret = swReactorProcess_start(serv);
}
else
{   
    ret = swReactorThread_start(serv);
}

如果設(shè)置了daemon模式, 在必要的參數(shù)檢查完后, 先將自己變?yōu)槭刈o(hù)進(jìn)程再fork manager進(jìn)程, 進(jìn)而創(chuàng)建reactor線程

主進(jìn)程先fork出manager進(jìn)程, manager進(jìn)程負(fù)責(zé)fork出worker進(jìn)程以及task_worker進(jìn)程。worker進(jìn)程之后進(jìn)入int swWorker_loop(swServer *serv, int worker_id), 也就是進(jìn)入自己的事件循環(huán), task_worker也是一樣, 進(jìn)入自己的事件循環(huán)。

static int swFactoryProcess_start(swFactory *factory);
//swFactoryProcess_start會(huì)調(diào)用swManager_start生成manager進(jìn)程
int swManager_start(swServer *serv);
// manager進(jìn)程會(huì)fork出worker進(jìn)程以及task_worker進(jìn)程

主進(jìn)程pthread_create出react線程, 主線程和react線程各自進(jìn)入自己的事件循環(huán), reactor線程執(zhí)行static int swReactorThread_loop(swThreadParam *param), 等待處理事件

//主線程執(zhí)行swReactorThread_start, 創(chuàng)建出reactor線程
int swReactorThread_start(swServer *serv);

結(jié)構(gòu)圖

swoole process模式結(jié)構(gòu)如下圖所示,

上圖并沒有考慮task_worker進(jìn)程, 在默認(rèn)情況下, task_worker進(jìn)程數(shù)為0

三. 請(qǐng)求處理流程(process模式) 3.1 reactor線程與worker進(jìn)程之間的通信

swoole master進(jìn)程與worker進(jìn)程之間的通信如下圖所示,

swoole使用SOCK_DGRAM, 而不是SOCK_STREAM, 這里是因?yàn)槊總€(gè)reactor線程負(fù)責(zé)處理多個(gè)請(qǐng)求, reactor接收到請(qǐng)求后會(huì)將信息轉(zhuǎn)發(fā)給worker進(jìn)程, 由worker進(jìn)程負(fù)責(zé)處理,如果使用SOCK_STREAM, worker進(jìn)程無法對(duì)tcp進(jìn)行分包, 進(jìn)而處理請(qǐng)求

swFactoryProcess_start函數(shù)中會(huì)根據(jù)worker進(jìn)程數(shù)創(chuàng)建對(duì)應(yīng)個(gè)數(shù)的套接字對(duì), 用于reactor線程與worker進(jìn)程通信(swPipeUnsock_create函數(shù))

假設(shè)reactor線程有2個(gè), worker進(jìn)程有3個(gè), 則reactor與worker之間的通信如下圖所示,

每個(gè)reactor線程負(fù)責(zé)監(jiān)聽幾個(gè)worker進(jìn)程, 每個(gè)worker進(jìn)程只有一個(gè)reactor線程監(jiān)聽(reactor_num<=worker_num)。swoole默認(rèn)使用worker_process_id % reactor_num對(duì)worker進(jìn)程進(jìn)行分配, 交給對(duì)應(yīng)的reactor線程進(jìn)行監(jiān)聽

reactor線程收到某個(gè)worker進(jìn)程的數(shù)據(jù)后會(huì)進(jìn)行處理, 值得注意的是, 這個(gè)reactor線程可能并不是發(fā)送請(qǐng)求的那個(gè)reactor線程。

reactor線程與worker進(jìn)程通信的數(shù)據(jù)包

//包頭
typedef struct _swDataHead
{
    int fd;
    uint32_t len;
    int16_t from_id;
    uint8_t type;
    uint8_t flags;
    uint16_t from_fd;
#ifdef SW_BUFFER_RECV_TIME
    double time;
#endif
} swDataHead;

//reactor線程向worker進(jìn)程發(fā)送的數(shù)據(jù), 也就是worker進(jìn)程收到的數(shù)據(jù)包
typedef struct
{
    swDataHead info;
    char data[SW_IPC_BUFFER_SIZE];
} swEventData;

//worker進(jìn)程向reactor線程發(fā)送的數(shù)據(jù), 也就是reactor線程收到的數(shù)據(jù)包
typedef struct
{
    swDataHead info;
    char data[0];
} swPipeBuffer;
3.2 請(qǐng)求處理

master進(jìn)程中的主線程負(fù)責(zé)監(jiān)聽端口(listen), 接受連接(accept, 產(chǎn)生一個(gè)fd), 接受連接后將請(qǐng)求分配給reactor線程, 默認(rèn)通過fd % reactor_num進(jìn)行分配, 之后通過epoll_ctl將fd加入到對(duì)應(yīng)reactor線程中(如果對(duì)應(yīng)的reactor線程正在執(zhí)行epoll_wait, 主線程會(huì)阻塞), 剛加入時(shí)監(jiān)聽寫事件, 如果直接監(jiān)聽讀事件, 可能會(huì)立刻被觸發(fā), 而監(jiān)聽寫事件可以允許reactor線程進(jìn)行一些初始化操作

//主線程執(zhí)行epoll_ctl將fd(新接受的連接)加入到reactor線程的監(jiān)聽隊(duì)列中
epoll_ctl(epfd, fd, ...);
//對(duì)應(yīng)的reactor線程如果正在執(zhí)行
epoll_wait(epfd, ...);

這種情況主線程會(huì)被阻塞(兩個(gè)線程同時(shí)操作epfd)

如果reactor線程沒有正在執(zhí)行epoll_wait, 主線程則不會(huì)被阻塞, 執(zhí)行成功后直接返回

reactor線程中fd的寫事件被觸發(fā), reactor線程負(fù)責(zé)處理, 發(fā)現(xiàn)是首次加入, 沒有數(shù)據(jù)可寫, 則開啟讀事件監(jiān)聽

reactor線程讀取到用戶的請(qǐng)求數(shù)據(jù), 一個(gè)請(qǐng)求的數(shù)據(jù)接收完后, 將數(shù)據(jù)轉(zhuǎn)發(fā)給worker進(jìn)程, 默認(rèn)是通過fd % worker_num進(jìn)行分配

reactor發(fā)送給worker進(jìn)程的數(shù)據(jù)包, 會(huì)包含一個(gè)頭部, 頭部中記錄了reactor的信息

如果發(fā)送的數(shù)據(jù)過大, 則需要將數(shù)據(jù)進(jìn)行分片, 限于篇幅, reactor的分片, 后續(xù)再進(jìn)行詳細(xì)講述

可能存在多個(gè)reactor線程同時(shí)向同一個(gè)worker進(jìn)程發(fā)送數(shù)據(jù)的情況, 故而swoole采用SOCK_DGRAM模式與worker進(jìn)程進(jìn)行通信, 通過每個(gè)數(shù)據(jù)包的包頭, worker進(jìn)程可以區(qū)分出是由哪個(gè)reactor線程發(fā)送的數(shù)據(jù)

worker進(jìn)程收到reactor發(fā)送的數(shù)據(jù)包后, 進(jìn)行處理, 處理完成后, 將數(shù)據(jù)發(fā)送給主進(jìn)程

worker進(jìn)程發(fā)送給主進(jìn)程的數(shù)據(jù)包, 也會(huì)包含一個(gè)頭部, 當(dāng)reactor線程收到數(shù)據(jù)包后, 能夠知道對(duì)應(yīng)的reactor線程, 請(qǐng)求的fd等信息

主進(jìn)程收到worker進(jìn)程發(fā)送的數(shù)據(jù)包, 這個(gè)會(huì)觸發(fā)某個(gè)reactor線程進(jìn)行處理

這個(gè)reactor線程并不一定是之前發(fā)送請(qǐng)求給worker進(jìn)程的那個(gè)reactor線程

主進(jìn)程的每個(gè)reactor線程都負(fù)責(zé)監(jiān)聽worker進(jìn)程發(fā)送的數(shù)據(jù)包, 每個(gè)worker發(fā)送的數(shù)據(jù)包只會(huì)由一個(gè)reactor線程進(jìn)行監(jiān)聽, 故而只會(huì)觸發(fā)一個(gè)reactor線程

reactor線程處理worker進(jìn)程發(fā)送的數(shù)據(jù)包, 如果是直接發(fā)送數(shù)據(jù)給客戶端, 則可以直接發(fā)送, 如果需要改變這個(gè)這個(gè)連接的監(jiān)聽狀態(tài)(例如close), 則需要先找到監(jiān)聽這個(gè)連接的reactor, 進(jìn)而改變這個(gè)連接的監(jiān)聽狀態(tài)

reactor處理線程與reactor監(jiān)聽線程可能并不是同一個(gè)線程

reactor監(jiān)聽線程負(fù)責(zé)監(jiān)聽客戶端發(fā)送的數(shù)據(jù), 進(jìn)而轉(zhuǎn)發(fā)給worker進(jìn)程

reactor處理線程負(fù)責(zé)監(jiān)聽worker進(jìn)程發(fā)送給主進(jìn)程的數(shù)據(jù), 進(jìn)而將數(shù)據(jù)發(fā)送給客戶端

四. gdb調(diào)試 4.1 process模式啟動(dòng)
//fork manager進(jìn)程
#0  0x00007ffff67dae64 in fork () from /lib64/libc.so.6
#1  0x00007ffff553888a in swoole_fork () at /root/code/swoole-src/src/core/base.c:186
#2  0x00007ffff556afb8 in swManager_start (serv=serv@entry=0x1353f60) at /root/code/swoole-src/src/server/manager.cc:164
#3  0x00007ffff5571dde in swFactoryProcess_start (factory=0x1353ff8) at /root/code/swoole-src/src/server/process.c:198
#4  0x00007ffff556ef8b in swServer_start (serv=0x1353f60) at /root/code/swoole-src/src/server/master.cc:651
#5  0x00007ffff55dc808 in zim_swoole_server_start (execute_data=, return_value=0x7fffffffac50)
    at /root/code/swoole-src/swoole_server.cc:2946
#6  0x00000000007bb068 in ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER () at /root/php-7.3.3/Zend/zend_vm_execute.h:980
#7  execute_ex (ex=0x7ffff7f850a8) at /root/php-7.3.3/Zend/zend_vm_execute.h:55485
#8  0x00000000007bbf58 in zend_execute (op_array=op_array@entry=0x7ffff5e7b340, return_value=return_value@entry=0x7ffff5e1d030)
    at /root/php-7.3.3/Zend/zend_vm_execute.h:60881
#9  0x0000000000737554 in zend_execute_scripts (type=type@entry=8, retval=0x7ffff5e1d030, retval@entry=0x0,
    file_count=file_count@entry=3) at /root/php-7.3.3/Zend/zend.c:1568
#10 0x00000000006db4d0 in php_execute_script (primary_file=primary_file@entry=0x7fffffffd050) at /root/php-7.3.3/main/main.c:2630
#11 0x00000000007be2f5 in do_cli (argc=2, argv=0x1165cd0) at /root/php-7.3.3/sapi/cli/php_cli.c:997
#12 0x000000000043fc1f in main (argc=2, argv=0x1165cd0) at /root/php-7.3.3/sapi/cli/php_cli.c:1389


// pthread_create reactor線程
#0  0x00007ffff552e960 in pthread_create@plt () from /usr/local/lib/php/extensions/no-debug-non-zts-20180731/swoole.so
#1  0x00007ffff5576959 in swReactorThread_start (serv=0x1353f60) at /root/code/swoole-src/src/server/reactor_thread.c:883
#2  0x00007ffff556f006 in swServer_start (serv=0x1353f60) at /root/code/swoole-src/src/server/master.cc:670
#3  0x00007ffff55dc808 in zim_swoole_server_start (execute_data=, return_value=0x7fffffffac50)
    at /root/code/swoole-src/swoole_server.cc:2946
#4  0x00000000007bb068 in ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER () at /root/php-7.3.3/Zend/zend_vm_execute.h:980
#5  execute_ex (ex=0x7fffffffab10) at /root/php-7.3.3/Zend/zend_vm_execute.h:55485
#6  0x00000000007bbf58 in zend_execute (op_array=op_array@entry=0x7ffff5e7b340, return_value=return_value@entry=0x7ffff5e1d030)
    at /root/php-7.3.3/Zend/zend_vm_execute.h:60881
#7  0x0000000000737554 in zend_execute_scripts (type=type@entry=8, retval=0x7ffff5e1d030, retval@entry=0x0,
    file_count=file_count@entry=3) at /root/php-7.3.3/Zend/zend.c:1568
#8  0x00000000006db4d0 in php_execute_script (primary_file=primary_file@entry=0x7fffffffd050) at /root/php-7.3.3/main/main.c:2630
#9  0x00000000007be2f5 in do_cli (argc=2, argv=0x1165cd0) at /root/php-7.3.3/sapi/cli/php_cli.c:997
#10 0x000000000043fc1f in main (argc=2, argv=0x1165cd0) at /root/php-7.3.3/sapi/cli/php_cli.c:1389
4.2 base模式啟動(dòng)
//base 模式下的啟動(dòng)
#0  0x00007ffff67dae64 in fork () from /lib64/libc.so.6
#1  0x00007ffff553888a in swoole_fork () at /root/code/swoole-src/src/core/base.c:186
#2  0x00007ffff5558557 in swProcessPool_spawn (pool=pool@entry=0x7ffff2d2a308, worker=0x7ffff2d2a778)
    at /root/code/swoole-src/src/network/process_pool.c:392
#3  0x00007ffff5558710 in swProcessPool_start (pool=0x7ffff2d2a308) at /root/code/swoole-src/src/network/process_pool.c:227
#4  0x00007ffff55741cf in swReactorProcess_start (serv=0x1353f60) at /root/code/swoole-src/src/server/reactor_process.cc:176
#5  0x00007ffff556f21d in swServer_start (serv=0x1353f60) at /root/code/swoole-src/src/server/master.cc:666
#6  0x00007ffff55dc808 in zim_swoole_server_start (execute_data=, return_value=0x7fffffffac50)
    at /root/code/swoole-src/swoole_server.cc:2946
#7  0x00000000007bb068 in ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER () at /root/php-7.3.3/Zend/zend_vm_execute.h:980
#8  execute_ex (ex=0x7ffff2d2a308) at /root/php-7.3.3/Zend/zend_vm_execute.h:55485
#9  0x00000000007bbf58 in zend_execute (op_array=op_array@entry=0x7ffff5e7b340, return_value=return_value@entry=0x7ffff5e1d030)
    at /root/php-7.3.3/Zend/zend_vm_execute.h:60881
#10 0x0000000000737554 in zend_execute_scripts (type=type@entry=8, retval=0x7ffff5e1d030, retval@entry=0x0,
    file_count=file_count@entry=3) at /root/php-7.3.3/Zend/zend.c:1568
#11 0x00000000006db4d0 in php_execute_script (primary_file=primary_file@entry=0x7fffffffd050) at /root/php-7.3.3/main/main.c:2630
#12 0x00000000007be2f5 in do_cli (argc=2, argv=0x1165cd0) at /root/php-7.3.3/sapi/cli/php_cli.c:997
#13 0x000000000043fc1f in main (argc=2, argv=0x1165cd0) at /root/php-7.3.3/sapi/cli/php_cli.c:1389
五. 參考

UNIX網(wǎng)絡(luò)編程

UNIX環(huán)境高級(jí)編程

https://wiki.swoole.com/

https://www.cnblogs.com/welhz...

https://www.cnblogs.com/JohnA...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/31602.html

相關(guān)文章

  • Swoole源碼學(xué)習(xí)-一個(gè)server創(chuàng)建

    摘要:若參數(shù)和字符串相等則返回。大于則返回大于的值,小于則返回小于的值。下面的中是增加一個(gè)這里我們顯然設(shè)置了主機(jī)和端口暫且跳過在這里我們看到調(diào)用了中的方法并且將初始化好的等傳了進(jìn)去,我們追進(jìn)去線程數(shù) 創(chuàng)建一個(gè)server 今天我們來研究一下swoole中server相關(guān)的源碼(版本是4.3.1),首先我們先從一段簡單代碼開始 $http = new SwooleHttpServer(127....

    macg0406 評(píng)論0 收藏0
  • Swoft 源碼剖析 - Swoole和Swoft那些事 (Http/Rpc服務(wù)篇)

    摘要:和服務(wù)關(guān)系最密切的進(jìn)程是中的進(jìn)程組,絕大部分業(yè)務(wù)處理都在該進(jìn)程中進(jìn)行。隨后觸發(fā)一個(gè)事件各組件通過該事件進(jìn)行配置文件加載路由注冊。事件每個(gè)請(qǐng)求到來時(shí)僅僅會(huì)觸發(fā)事件。服務(wù)器生命周期和服務(wù)基本一致,詳情參考源碼剖析功能實(shí)現(xiàn) 作者:bromine鏈接:https://www.jianshu.com/p/4c0...來源:簡書著作權(quán)歸作者所有,本文已獲得作者授權(quán)轉(zhuǎn)載,并對(duì)原文進(jìn)行了重新的排版。S...

    張漢慶 評(píng)論0 收藏0
  • Swoole源碼研究】深入理解Swoole協(xié)程實(shí)現(xiàn)

    摘要:此時(shí)的協(xié)程實(shí)現(xiàn)無法完美的支持語法,其根本原因在于沒有保存棧信息。這是因?yàn)檎{(diào)用函數(shù)時(shí),底層指令已經(jīng)將入棧了。協(xié)程創(chuàng)建時(shí),底層通過函數(shù)實(shí)現(xiàn)了棧的創(chuàng)建創(chuàng)建并初始化棧為結(jié)構(gòu)分配空間創(chuàng)建新的執(zhí)行數(shù)據(jù)結(jié)構(gòu)從代碼中可以看到結(jié)構(gòu)是直接存儲(chǔ)在棧的底部。 作者:李樂??本文基于Swoole-4.3.2和PHP-7.1.0版本 Swoole協(xié)程簡介 ??Swoole4為PHP語言提供了強(qiáng)大的CSP協(xié)程編程模...

    darkerXi 評(píng)論0 收藏0
  • Swoole 在 Swoft 應(yīng)用

    摘要:在中的應(yīng)用官網(wǎng)源碼解讀號(hào)外號(hào)外歡迎大家我們開發(fā)組定了一個(gè)就線下聚一次的小目標(biāo)上一篇源碼解讀反響還不錯(cuò)不少同學(xué)推薦再加一篇講解一下中使用到的功能幫助大家開啟的實(shí)戰(zhàn)之旅服務(wù)器開發(fā)涉及到的相關(guān)技術(shù)領(lǐng)域的知識(shí)非常多不日積月累打好基礎(chǔ)是很難真正 date: 2017-12-14 21:34:51title: swoole 在 swoft 中的應(yīng)用 swoft 官網(wǎng): https://www.sw...

    EscapedDog 評(píng)論0 收藏0
  • Swoole入門到實(shí)戰(zhàn)(一):PHP7&Swoole源碼安裝、玩轉(zhuǎn)網(wǎng)絡(luò)通信引擎、異步非堵塞I

    摘要:服務(wù)重點(diǎn)基本概述協(xié)議是基于的一種新的網(wǎng)絡(luò)協(xié)議。被調(diào)用者通過狀態(tài)通知機(jī)制等來通知調(diào)用者,或通過回調(diào)函數(shù)來處理結(jié)果阻塞和非阻塞關(guān)注的是調(diào)用者等待被調(diào)用者返回調(diào)用結(jié)果時(shí)的狀態(tài)。 一、PHP7源碼安裝和Swoole源碼編譯安裝 1.1 PHP7源碼安裝 1.1.1 獲取源碼與安裝 ????獲取PHP7源碼:www.php.net tar -xzvf ... # 解壓命令 ./configur...

    weakish 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<