稍微整理了一下流程图,便于以后回忆下
总结几点如下:
首先主进程监听pipe_master事件,
子进程监听pipe_worker事件
通过主进程派生的线程
swReactorThread *thread = swServer_get_thread(serv, reactor_id);
swReactor *reactor = &thread->reactor;
reactor->setHandle(reactor, SW_FD_CLOSE, swReactorThread_onClose); reactor->setHandle(reactor, SW_FD_UDP, swReactorThread_onPackage);/** * receive data from worker process pipe */当子进程处理完数据要发送给客户端的时候,就会往pipe_worker写数据,此时会触发pipe_master的读操作reactor->setHandle(reactor, SW_FD_PIPE, swReactorThread_onPipeReceive);将获取的数据直接发送给客户端,如果写入失败,就会将数据写入到conn->out_buffer中进行缓存,并且会addif (reactor->set(reactor, fd, SW_EVENT_TCP | SW_EVENT_WRITE | SW_EVENT_READ) < 0 && (errno == EBADF || errno == ENOENT))
add的这个事件意味着会触发下面所介绍的swReactorThread_onWrite继续发送数据/** * [ReactorThread] worker pipe can write. */reactor->setHandle(reactor, SW_FD_PIPE | SW_EVENT_WRITE, swReactorThread_onPipeWrite);当主进程accept获取获取了数据要发送给子进程的pipe_worker时,如果write失败,就会重新add此事件,并触发,thread->reactor.add(&thread->reactor, pipe_fd, SW_FD_PIPE | SW_EVENT_WRITE);其中write失败的数据会写入到thread->buffer_pipe中进行缓存,这样通过以上事件就可以发送缓存的数据//上面介绍的swReactorThread_onPipeReceive写入失败后会触发 reactor->setHandle(reactor, SW_FD_TCP | SW_EVENT_WRITE, swReactorThread_onWrite);
//tcp receive//Thread mode must copy the data. //will free after onFinish if (serv->open_eof_check) {将数据缓存在conn->in_buffer字段中 reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_buffer_check_eof); } else if (serv->open_length_check) {数据缓存在conn->object字段中 reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_buffer_check_length); } else if (serv->open_http_protocol) {数据缓存在conn->object字段中 reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_http_request); } else { reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_no_buffer); }
设置了线程的监听事件,
第一个触发点就是当主进程
ret = serv->reactor_threads[reactor_id].reactor.add(&(serv->reactor_threads[reactor_id].reactor), new_fd, SW_FD_TCP | SW_EVENT_READ);
会触发以上的swReactorThread_onReceive_http_request等事件接受fd的read数据
然后介绍子进程的pipe_workerSwooleG.main_reactor->add(SwooleG.main_reactor, pipe_worker, SW_FD_PIPE);/** * receive data from reactor */主进程accept数据后就写入pipe_master从而触发子进程的swWorker_onPipeReceive,SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE, swWorker_onPipeReceive);在这里需要注意的是在发送时已经将数据划分为多个包,每个包的状态如下task->info.typeSW_EVENT_PACKAGE_STARTSW_EVENT_PACKAGE_END当SW_EVENT_PACKAGE_START时候不发送,期间将缓存放在SwooleWG.buffer_input中缓存(每个子进程一个缓存池),
直到接收到了SW_EVENT_PACKAGE_END包后才会真正的处理数据,也就是接收完整后才调用factory->onTask(factory, task);SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE | SW_EVENT_WRITE, swWorker_onPipeWrite);/** * pipe can write. */当子进程获取了处理后的数据要发送结果给pipe_master时,如果发送失败,数据就会放入p->worker_buffer中进行缓存,
然后添加句柄SwooleG.main_reactor->add(SwooleG.main_reactor, pipefd, SW_FD_PIPE | SW_EVENT_WRITE);触发回调函数其中swoole有ontask的执行任务功能,在我看来和上述的子进程模式一样,只不过单独开辟了一堆子进程来处理所谓你需要执行“任务”功能而设计,在我看来事相同实现方式处理不同需求swoole其中设计了心跳,单独开辟了一个线程swServer_heartbeat_check,每一秒钟就会遍历所有connect的fd句柄,
其中根据conn->last_time最后操作时间判定是否超时,如果超时就调用factory->notify(&serv->factory, ¬ify_ev);其中notify_ev.type = SW_EVENT_CLOSE;然后子进程接收到了该信号就会关闭响应连接,从而处理超时情况。上面介绍了很多将数据缓存的位置比如conn->in_buffer, conn->object, thread->buffer_pipe, p->worker_buffer,其中前两个大家需要注意的是conn是具体某个连接,并且是对外的,因为由于外界连接我们无法预计,所以用了异步模型,为了区分每个连接过来的数据就必须用唯一的conn来关联,后两组是每组进程一个缓存池,因为后两组是管道通信,在我们完整拿到了某个conn的数据,以及完整的要发送client完整数据,对我们来说是可控的,所以就可以一下子发送出去,保证这批发送时同一个连接的数据,不会有不同连接数据交叉的情况,所以就要求我们管道之间通信必须保证是同一个连接的完整数据,否则缓冲区就乱了,这也是为什么数据包可以分为start,和end的原因,因为一定发过来是同一个连接数据 ,
看代码心里一直有个疑问就是
read(event->fd, &task, sizeof(task)
类似这样的直接读取一个struct大小,如何保证大小正合适,按理说这是个不严密的写法,但是作者不会视而不见,
这样写应该是有考虑吧,我是百思不得其解,不知道谁能解答一下
重要的步骤:核心四个文件Server.c FactoryProcess.c Worker.c RectorThread.c1factory->object = object; factory->dispatch = swFactoryProcess_dispatch;factory->finish = swFactoryProcess_finish;/**
结束请求子进程是factory->finish = swFactoryProcess_finish;但是主进程是重新赋值的,这点需要注意//主进程需要设置为直写模式 factory->finish = swFactory_finish;其中关闭连接在此实现
*/factory->start = swFactoryProcess_start;factory->notify = swFactoryProcess_notify;factory->shutdown = swFactoryProcess_shutdown;factory->end = swFactoryProcess_end;factory->onTask = NULL;factory->onFinish = NULL;2/** * worker main loop */SwooleG.main_reactor->add(SwooleG.main_reactor, pipe_worker, SW_FD_PIPE);SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE, swWorker_onPipeReceive);//write事件为了write失败发送缓冲区而建立的事件p->worker_buffer SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE | SW_EVENT_WRITE, swWorker_onPipeWrite);/** * proxy模式 * 在单独的n个线程中接受维持TCP连接 */reactor->setHandle(reactor, SW_FD_CLOSE, swReactorThread_onClose); reactor->setHandle(reactor, SW_FD_UDP, swReactorThread_onPackage);//线程接受work输出给client的内容 reactor->setHandle(reactor, SW_FD_PIPE, swReactorThread_onPipeReceive); reactor->setHandle(reactor, SW_FD_PIPE | SW_EVENT_WRITE, swReactorThread_onPipeWrite);//write事件为了write失败发送缓冲区而建立的事件conn_bufferreactor->setHandle(reactor, SW_FD_TCP | SW_EVENT_WRITE, swReactorThread_onWrite);//下面是线程接受accept的fd套接字reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_buffer_check_eof);reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_buffer_check_length); reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_http_request); reactor->setHandle(reactor, SW_FD_TCP, swReactorThread_onReceive_no_buffer);