摘要:若參數和字符串相等則返回。大于則返回大于的值,小于則返回小于的值。下面的中是增加一個這里我們顯然設置了主機和端口暫且跳過在這里我們看到調用了中的方法并且將初始化好的等傳了進去,我們追進去線程數
創建一個server
今天我們來研究一下swoole中server相關的源碼(版本是4.3.1),首先我們先從一段簡單代碼開始
$http = new SwooleHttpServer("127.0.0.1",9501); $http->on("request", function ($request, $response) { $response->header("Content-Type", "text/html; charset=utf-8"); $response->end("Hello Swoole. #".rand(1000, 9999)."
"); }); $http->start();
上面的代碼在本地起了一個服務監聽9501端口,下圖是瀏覽器請求的接口
好了我們開始,首先分析一下上面的代碼其實是調用了一下SwooleHttpServer這個類,然后分別調用了下面三個方法:
__construct(初始化)
on(注冊事件)
start(啟動server)
這三個方法都在./swoole_server.cc中,初始化是在MINT階段加載swoole時執行的./swoole_http_server.cc中的swoole_http_server_init方法
void swoole_http_server_init(int module_number) { SWOOLE_INIT_CLASS_ENTRY_EX(swoole_http_server, "SwooleHttpServer", "swoole_http_server", NULL, NULL, swoole_server); ... }
上面可以看到一些命名,注意最后的參數,這里繼承了swoole_server,所以上面幾個方法的注冊實際在swoole_server.c中
void swoole_server_init(int module_number) { SWOOLE_INIT_CLASS_ENTRY(swoole_server, "SwooleServer", "swoole_server", NULL, swoole_server_methods); ...... } static zend_function_entry swoole_server_methods[] = { PHP_ME(swoole_server, __construct, arginfo_swoole_server__construct, ZEND_ACC_PUBLIC) PHP_ME(swoole_server, on, arginfo_swoole_server_on, ZEND_ACC_PUBLIC) PHP_ME(swoole_server, start, arginfo_swoole_void, ZEND_ACC_PUBLIC) ...... }
其他的暫且略過,上面可以看到swoole_server_methods中定義的這三個方法,我們首先來看下__construct這個方法,首先在arginfo_swoole_server__construct中定義了可以接收的參數
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_server__construct, 0, 0, 1) ZEND_ARG_INFO(0, host)//主機 ZEND_ARG_INFO(0, port)//端口 ZEND_ARG_INFO(0, mode)//模式 ZEND_ARG_INFO(0, sock_type)//sock類型 ZEND_END_ARG_INFO()
好了下面我們正式進入__construct方法
__construct(server的構造)static PHP_METHOD(swoole_server, __construct) { size_t host_len = 0; char *serv_host; zend_long sock_type = SW_SOCK_TCP;//定義默認socket類型SW_SOCK_TCP zend_long serv_port = 0; zend_long serv_mode = SW_MODE_PROCESS;//定義默認模式SW_MODE_PROCESS //only cli env if (!SWOOLE_G(cli)) { swoole_php_fatal_error(E_ERROR, "swoole_server only can be used in PHP CLI mode."); RETURN_FALSE; } if (SwooleG.main_reactor)//初始化main_reactor { SwooleG.origin_main_reactor = SwooleG.main_reactor; SwooleG.main_reactor = NULL; } if (SwooleG.serv != NULL)//判斷server狀態 { swoole_php_fatal_error(E_ERROR, "server is running. unable to create swoole_server."); RETURN_FALSE; } swServer *serv = (swServer *) sw_malloc(sizeof (swServer));
上面是分配一塊swServer結構的內存,往下走
swServer_init(serv);
初始化 server,我們跟進去,代碼在./src/server/master.cc中,在這里對swServer中的一些配置做了初始化
void swServer_init(swServer *serv) { swoole_init();
上面的swoole_init重點對SwooleG進行初始化存放swoole一些全局信息,包括
running (啟動狀態,這里設置為1)
enable_coroutine(協程啟用狀態,這里設置為1)
log_fd (日志fd)
write_log
fatal_error
cpu_num
uname
pid
memory_pool
max_sockets (最大sockets數量 這里是1024)
...
往下走
//對serv清零 bzero(serv, sizeof(swServer)); //設置默認模式為SW_MODE_BASE serv->factory_mode = SW_MODE_BASE; //設置reactor數量,這里是cpu核數 和 SW_REACTOR_MAX_THREAD(8) 取小的 serv->reactor_num = SW_REACTOR_NUM > SW_REACTOR_MAX_THREAD ? SW_REACTOR_MAX_THREAD : SW_REACTOR_NUM; serv->dispatch_mode = SW_DISPATCH_FDMOD; //設置默認worker_num跟cpu核數相同 serv->worker_num = SW_CPU_NUM; //設置最大鏈接數,這里SW_MAX_CONNECTION是100000 和 上面設置的1024 取小顯然 1024 serv->max_connection = SW_MIN(SW_MAX_CONNECTION, SwooleG.max_sockets); //設置最大等待時間,這里SW_WORKER_MAX_WAIT_TIME為30 serv->max_wait_time = SW_WORKER_MAX_WAIT_TIME; //http server serv->http_parse_post = 1; serv->http_compression = 1; serv->http_compression_level = 1; // Z_BEST_SPEED serv->upload_tmp_dir = sw_strdup("/tmp"); serv->buffer_input_size = SW_BUFFER_INPUT_SIZE; serv->buffer_output_size = SW_BUFFER_OUTPUT_SIZE; serv->task_ipc_mode = SW_TASK_IPC_UNIXSOCK; serv->enable_coroutine = 1; /** * alloc shared memory(分配共享內存) */ serv->stats = (swServerStats *) SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(swServerStats)); if (serv->stats == NULL) { swError("[Master] Fatal Error: failed to allocate memory for swServer->stats."); } serv->gs = (swServerGS *) SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(swServerGS)); if (serv->gs == NULL) { swError("[Master] Fatal Error: failed to allocate memory for swServer->gs."); } 將server放入SwooleG中 SwooleG.serv = serv; }
好了,server初始化完成,下面再回到__construct方法中
//解析參數校驗參數格式 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lll", &serv_host, &host_len, &serv_port, &serv_mode, &sock_type) == FAILURE) { swoole_php_fatal_error(E_ERROR, "invalid swoole_server parameters."); RETURN_FALSE; } //如果不是SW_MODE_BASE或者SW_MODE_PROCESS模式報錯,這里可以看到目前server支持這兩種模式 if (serv_mode != SW_MODE_BASE && serv_mode != SW_MODE_PROCESS) { swoole_php_fatal_error(E_ERROR, "invalid $mode parameters %d.", (int) serv_mode); RETURN_FALSE; } //SW_MODE_BASE模式重置reactor_num和worker_num為1 if (serv_mode == SW_MODE_BASE) { serv->reactor_num = 1; serv->worker_num = 1; } //將serv_mode賦給factory_mode serv->factory_mode = serv_mode; //php_sw_server_callbacks清零 bzero(php_sw_server_callbacks, sizeof(zval*) * PHP_SWOOLE_SERVER_CALLBACK_NUM);
函數 strcasecmp()用來比較參數s1和s2字符串,比較時會自動忽略大小寫的差異。若參數s1和s2字符串相等則返回0。s1大于s2則返回大于0 的值,s1 小于s2 則返回小于0的值。下面的if中是增加一個systemd socket.這里我們顯然設置了主機和端口暫且跳過
if (serv_port == 0 && strcasecmp(serv_host, "SYSTEMD") == 0) { if (swServer_add_systemd_socket(serv) <= 0) { swoole_php_fatal_error(E_ERROR, "failed to add systemd socket."); RETURN_FALSE; } } else { swListenPort *port = swServer_add_port(serv, sock_type, serv_host, serv_port);
在這里我們看到調用了master.cc中的swServer_add_port方法并且將初始化好的server,sock_type,serv_host,serv_port等傳了進去,我們追進去
if (!port) { zend_throw_exception_ex( swoole_exception_ce_ptr, errno, "failed to listen server port[%s:" ZEND_LONG_FMT "]. Error: %s[%d].", serv_host, serv_port, strerror(errno), errno ); RETURN_FALSE; } } zval *server_object = getThis(); zval connection_iterator_object; object_init_ex(&connection_iterator_object, swoole_connection_iterator_ce_ptr); zend_update_property(swoole_server_ce_ptr, server_object, ZEND_STRL("connections"), &connection_iterator_object); swConnectionIterator *i = (swConnectionIterator *) emalloc(sizeof(swConnectionIterator)); bzero(i, sizeof(swConnectionIterator)); i->serv = serv; swoole_set_object(&connection_iterator_object, i); zend_update_property_stringl(swoole_server_ce_ptr, server_object, ZEND_STRL("host"), serv_host, host_len); zend_update_property_long(swoole_server_ce_ptr, server_object, ZEND_STRL("port"), (long) serv->listen_list->port); zend_update_property_long(swoole_server_ce_ptr, server_object, ZEND_STRL("mode"), serv->factory_mode); zend_update_property_long(swoole_server_ce_ptr, server_object, ZEND_STRL("type"), sock_type); swoole_set_object(server_object, serv); zval *ports = sw_malloc_zval(); array_init(ports); server_port_list.zports = ports; #ifdef HT_ALLOW_COW_VIOLATION HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(ports)); #endif swListenPort *ls; LL_FOREACH(serv->listen_list, ls) { php_swoole_server_add_port(serv, ls); } server_port_list.primary_port = (swoole_server_port_property *) serv->listen_list->ptr; zend_update_property(swoole_server_ce_ptr, server_object, ZEND_STRL("ports"), ports); }
struct _swServer { /** 線程數 * reactor thread/process num */ uint16_t reactor_num; /** * worker process num */ uint16_t worker_num; /** * The number of pipe per reactor maintenance */ uint16_t reactor_pipe_num; uint8_t factory_mode; uint8_t dgram_port_num; /** * package dispatch mode */ uint8_t dispatch_mode; /** * No idle work process is available. */ uint8_t scheduler_warning; int worker_uid; int worker_groupid; /** * max connection num */ uint32_t max_connection; /** * worker process max request */ uint32_t max_request; int udp_socket_ipv4; int udp_socket_ipv6; uint32_t max_wait_time; /*----------------------------Reactor schedule--------------------------------*/ uint16_t reactor_round_i; uint16_t reactor_next_i; uint16_t reactor_schedule_count; sw_atomic_t worker_round_id; /** * run as a daemon process */ uint32_t daemonize :1; /** * have dgram socket */ uint32_t have_dgram_sock :1; /** * have stream socket */ uint32_t have_stream_sock :1; /** * open cpu affinity setting */ uint32_t open_cpu_affinity :1; /** * disable notice when use SW_DISPATCH_ROUND and SW_DISPATCH_QUEUE */ uint32_t disable_notify :1; /** * discard the timeout request */ uint32_t discard_timeout_request :1; /** * parse x-www-form-urlencoded data */ uint32_t http_parse_post :1; /** * http content compression */ uint32_t http_compression :1; /** * handle static files */ uint32_t enable_static_handler :1; /** * enable onConnect/onClose event when use dispatch_mode=1/3 */ uint32_t enable_unsafe_event :1; /** * waiting for worker onConnect callback function to return */ uint32_t enable_delay_receive :1; /** * asynchronous reloading */ uint32_t reload_async :1; /** * enable coroutine in task worker */ uint32_t task_enable_coroutine :1; /** * slowlog */ uint32_t trace_event_worker :1; /** * yield coroutine when the output buffer is full */ uint32_t send_yield :1; /** * enable coroutine */ uint32_t enable_coroutine :1; /** * disable multi-threads */ uint32_t single_thread :1; /** * heartbeat check time */ uint16_t heartbeat_idle_time; uint16_t heartbeat_check_interval; int *cpu_affinity_available; int cpu_affinity_available_num; double send_timeout; uint16_t listen_port_num; time_t reload_time; time_t warning_time; /* buffer output/input setting*/ uint32_t buffer_output_size; uint32_t buffer_input_size; void *ptr2; void *private_data_3; swFactory factory; swListenPort *listen_list; pthread_t heartbeat_pidt; /** * task process */ uint16_t task_worker_num; uint8_t task_ipc_mode; uint16_t task_max_request; swPipe *task_notify; swEventData *task_result; /** * user process */ uint16_t user_worker_num; swUserWorker_node *user_worker_list; swHashMap *user_worker_map; swWorker *user_workers; swReactorThread *reactor_threads; swWorker *workers; swChannel *message_box; swServerStats *stats; swServerGS *gs; #ifdef HAVE_PTHREAD_BARRIER pthread_barrier_t barrier; #endif swConnection *connection_list; swSession *session_list; /** * temporary directory for HTTP uploaded file. */ char *upload_tmp_dir; /** * http compression level for gzip/br */ uint8_t http_compression_level; /** * http static file directory */ char *document_root; uint16_t document_root_len; /** * master process pid */ char *pid_file; /** * stream */ char *stream_socket; int stream_fd; swProtocol stream_protocol; int last_stream_fd; swLinkedList *buffer_pool; #ifdef SW_BUFFER_RECV_TIME double last_receive_usec; #endif int manager_alarm; /** * message queue key */ uint64_t message_queue_key; /** * slow request log */ uint8_t request_slowlog_timeout; FILE *request_slowlog_file; swReactor *reactor_ptr; //Main Reactor swFactory *factory_ptr; //Factory swLinkedList *hooks[SW_MAX_HOOK_TYPE]; void (*onStart)(swServer *serv); void (*onManagerStart)(swServer *serv); void (*onManagerStop)(swServer *serv); void (*onShutdown)(swServer *serv); void (*onPipeMessage)(swServer *, swEventData *); void (*onWorkerStart)(swServer *serv, int worker_id); void (*onWorkerStop)(swServer *serv, int worker_id); void (*onWorkerExit)(swServer *serv, int worker_id); void (*onWorkerError)(swServer *serv, int worker_id, pid_t worker_pid, int exit_code, int signo); void (*onUserWorkerStart)(swServer *serv, swWorker *worker); /** * Client */ int (*onReceive)(swServer *, swEventData *); int (*onPacket)(swServer *, swEventData *); void (*onClose)(swServer *serv, swDataHead *); void (*onConnect)(swServer *serv, swDataHead *); void (*onBufferFull)(swServer *serv, swDataHead *); void (*onBufferEmpty)(swServer *serv, swDataHead *); /** * Task Worker */ int (*onTask)(swServer *serv, swEventData *data); int (*onFinish)(swServer *serv, swEventData *data); /** * Server method */ int (*send)(swServer *serv, int session_id, void *data, uint32_t length); int (*sendfile)(swServer *serv, int session_id, char *file, uint32_t l_file, off_t offset, size_t length); int (*sendwait)(swServer *serv, int session_id, void *data, uint32_t length); int (*close)(swServer *serv, int session_id, int reset); int (*notify)(swServer *serv, swConnection *conn, int event); int (*feedback)(swServer *serv, int session_id, int event); int (*dispatch_func)(swServer *, swConnection *, swSendData *); };
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/31580.html
摘要:和服務關系最密切的進程是中的進程組,絕大部分業務處理都在該進程中進行。隨后觸發一個事件各組件通過該事件進行配置文件加載路由注冊。事件每個請求到來時僅僅會觸發事件。服務器生命周期和服務基本一致,詳情參考源碼剖析功能實現 作者:bromine鏈接:https://www.jianshu.com/p/4c0...來源:簡書著作權歸作者所有,本文已獲得作者授權轉載,并對原文進行了重新的排版。S...
摘要:易用穩定,本次想通過對的學習和個人解析,吸收框架的思想和設計知識,加強自己對的認知和理解。當然,筆者能力水平有限,后續的文章如有錯誤,還請指出和諒解。目錄如下后續添加文章都會記錄在此服務啟動過程以及主體設計流程源碼解析 前言 swoole是什么?官網的原話介紹是這樣的: Swoole 使用純 C 語言編寫,提供了 PHP 語言的異步多線程服務器,異步 TCP/UDP 網絡客戶端,異步 ...
摘要:進程可以使用函數向進程投遞新的任務。當前的進程在調用回調函數時會將進程狀態切換為忙碌,這時將不再接收新的,當函數返回時會將進程狀態切換為空閑然后繼續接收新的。當進程投遞的任務在中完成時,進程會通過方法將任務處理的結果發送給進程。 swoole——從入門到放棄(一) 一、swoole的源碼包安裝 下載swoole源碼:git clone https://gitee.com/swoole...
摘要:的部分是基于以及協議的。例如父進程向中寫入子進程從中讀取子進程向中寫入父進程從中讀取。默認使用對進程進行分配交給對應的線程進行監聽線程收到某個進程的數據后會進行處理值得注意的是這個線程可能并不是發送請求的那個線程。 作者:施洪寶 一. 基礎知識 1.1 swoole swoole是面向生產環境的php異步網絡通信引擎, php開發人員可以利用swoole開發出高性能的server服務。...
摘要:服務重點基本概述協議是基于的一種新的網絡協議。被調用者通過狀態通知機制等來通知調用者,或通過回調函數來處理結果阻塞和非阻塞關注的是調用者等待被調用者返回調用結果時的狀態。 一、PHP7源碼安裝和Swoole源碼編譯安裝 1.1 PHP7源碼安裝 1.1.1 獲取源碼與安裝 ????獲取PHP7源碼:www.php.net tar -xzvf ... # 解壓命令 ./configur...
閱讀 1405·2021-11-25 09:43
閱讀 2261·2021-09-27 13:36
閱讀 1114·2021-09-04 16:40
閱讀 1957·2019-08-30 11:12
閱讀 3309·2019-08-29 14:14
閱讀 566·2019-08-28 17:56
閱讀 1320·2019-08-26 13:50
閱讀 1246·2019-08-26 13:29