结合上面几篇的分析,我们已经知道了reactor的主事件处理过程和在reactor上面注册的回调逻辑,这篇我们开始分析reactor和回调处理的逻辑,看看reactor和worker的交互是如何做的。首先,我们分析的代码如下图所示:
SwooleG.main_reactor->add(SwooleG.main_reactor, pipe_worker, SW_FD_PIPE | SW_EVENT_READ);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE, swWorker_onPipeReceive);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_WRITE, swReactor_onWrite);
这些代码位于E:\swoole-src-master\src\network\Work.c里面,我们从swWorker_onPipeReceive开始分析。
//从reactor接收到数据,其中reactor为主事件处理器,而event为事件相关的对象
static int swWorker_onPipeReceive(swReactor *reactor, swEvent *event)
{
swEventData task;//此次交互数据相关信息,后面分析流程中可以看到
swServer *serv = reactor->ptr;//获取server信息,主要是server里面携带了PHP侧的回调函数
swFactory *factory = &serv->factory;//获取factory信息
int ret;
read_from_pipe:
if (read(event->fd, &task, sizeof(task)) > 0)//从event->fd中阻塞读取信息,信息存放在task中,从管道中读取,一般情况下可以读到数据。
{
ret = swWorker_onTask(factory, &task);//数据给到worker处理,这里给到的task是个完整的task信息,worker可以直接处理
#ifndef SW_WORKER_RECV_AGAIN
//这里有个大包的处理流程
if (task.info.type == SW_EVENT_PACKAGE_START)//task的类型做判断,数据是分多部分传输的
#endif
{
//没有数据
if (ret < 0 && errno == EAGAIN)
{
return SW_OK;
}
else if (ret > 0) //未读取完全,根据worker的处理结果判断
{
goto read_from_pipe;
}
}
return ret;
}
return SW_ERR;
}
int swWorker_onTask(swFactory *factory, swEventData *task)
{
swServer *serv = factory->ptr;//获取server对象
swString *package = NULL;//用于表示请求体信息,不包括头部
swDgramPacket *header;//用于UDP的,表示包体头部信息
#ifdef SW_USE_OPENSSL
swConnection *conn;
#endif
factory->last_from_id = task->info.from_id;//关联相应的ID
serv->last_session_id = task->info.fd;//关联相应的ID
swWorker *worker = SwooleWG.worker;//全局变量SwooleWG是对worker进程的抽象
//标记worker的状态为繁忙中
worker->status = SW_WORKER_BUSY;
switch (task->info.type)//开始处理task的类型
{
case SW_EVENT_TCP:
case SW_EVENT_PACKAGE:
//discard data
if (swWorker_discard_data(serv, task) == SW_TRUE)
{
break;
}
do_task:
{
worker->request_time = serv->gs->now;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = task->info.time;
#endif
serv->onReceive(serv, task);
worker->request_time = 0;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = 0;
#endif
worker->traced = 0;
worker->request_count++;
sw_atomic_fetch_add(&serv->stats->request_count, 1);
}
if (task->info.type == SW_EVENT_PACKAGE_END)
{
package->length = 0;
}
break;
//chunk package
case SW_EVENT_PACKAGE_START:
case SW_EVENT_PACKAGE_END:
//discard data
if (swWorker_discard_data(serv, task) == SW_TRUE)
{
break;
}
package = swWorker_get_buffer(serv, task->info.from_id);
if (task->info.len > 0)
{
//merge data to package buffer
swString_append_ptr(package, task->data, task->info.len);
}
//package end
if (task->info.type == SW_EVENT_PACKAGE_END)
{
goto do_task;
}
break;
case SW_EVENT_UDP:
case SW_EVENT_UDP6:
case SW_EVENT_UNIX_DGRAM:
package = swWorker_get_buffer(serv, task->info.from_id);
swString_append_ptr(package, task->data, task->info.len);
if (package->offset == 0)
{
header = (swDgramPacket *) package->str;
package->offset = header->length;
}
//one packet
if (package->offset == package->length - sizeof(swDgramPacket))
{
worker->request_count++;
worker->request_time = serv->gs->now;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = task->info.time;
#endif
sw_atomic_fetch_add(&serv->stats->request_count, 1);
serv->onPacket(serv, task);
worker->request_time = 0;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = 0;
#endif
worker->traced = 0;
worker->request_count++;
swString_clear(package);
}
break;
case SW_EVENT_CLOSE:
#ifdef SW_USE_OPENSSL
conn = swServer_connection_verify_no_ssl(serv, task->info.fd);
if (conn && conn->ssl_client_cert.length > 0)
{
sw_free(conn->ssl_client_cert.str);
bzero(&conn->ssl_client_cert, sizeof(conn->ssl_client_cert.str));
}
#endif
factory->end(factory, task->info.fd);
break;
case SW_EVENT_CONNECT:
#ifdef SW_USE_OPENSSL
//SSL client certificate
if (task->info.len > 0)
{
conn = swServer_connection_verify_no_ssl(serv, task->info.fd);
conn->ssl_client_cert.str = sw_strndup(task->data, task->info.len);
conn->ssl_client_cert.size = conn->ssl_client_cert.length = task->info.len;
}
#endif
if (serv->onConnect)
{
serv->onConnect(serv, &task->info);
}
break;
case SW_EVENT_BUFFER_FULL:
if (serv->onBufferFull)
{
serv->onBufferFull(serv, &task->info);
}
break;
case SW_EVENT_BUFFER_EMPTY:
if (serv->onBufferEmpty)
{
serv->onBufferEmpty(serv, &task->info);
}
break;
case SW_EVENT_FINISH:
serv->onFinish(serv, task);
break;
case SW_EVENT_PIPE_MESSAGE:
serv->onPipeMessage(serv, task);
break;
default:
swWarn("[Worker] error event[type=%d]", (int )task->info.type);
break;
}
//worker idle
worker->status = SW_WORKER_IDLE;
//maximum number of requests, process will exit.
if (!SwooleWG.run_always && worker->request_count >= SwooleWG.max_request)
{
swWorker_stop();
}
return SW_OK;
}