业务数据处理一定要单独开线程吗 在 《one thread one loop 思想》一文我们介绍了一个 loop 的主要结构一般如下所示:
while (!m_bQuitFlag) { epoll_or_select_func(); handle_io_events(); handle_other_things(); } 对于一些业务逻辑处理比较简单、不会太耗时的应用来说,handle_io_events() 方法除了收发数据也可以直接用来直接做业务的处理,即其结构如下:
void handle_io_events() { //收发数据 recv_or_send_data(); //解包并处理数据 decode_packages_and_process(); } 其中 recv_or_send_data() 方法中调用 send/recv API 进行实际的网络数据收发。以收数据为例,收完数据存入接收缓冲区后,接下来进行解包处理,然后进行业务处理,例如一个登陆数据包,其业务就是验证登陆的账户密码是否正确、记录其登陆行为等等。从程序函数调用堆栈来看,这些业务处理逻辑其实是直接在网络收发数据线程中处理的。我的意思是:网络线程调用 handle_io_events() 方法,handle_io_events() 方法调用 decode_packages_and_process() 方法,decode_packages_and_process() 方法做具体的业务逻辑处理。
需要注意的是,为了让网络层与业务层脱耦,网络层中通常会提供一些回调函数的接口,这些回调函数我们将其指向具体的业务处理函数。以 libevent 网络库的用法为例:
int main(int argc, char **argv) { struct event_base *base; struct evconnlistener *listener; struct event *signal_event; struct sockaddr_in sin; base = event_base_new(); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(PORT); //listener_cb是我们自定义回调函数 listener = evconnlistener_new_bind(base, listener_cb, (void *)base, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&sin, sizeof(sin)); if (!listener) { fprintf(stderr, "Could not create a listener!\n"); return 1; } //signal_cb是我们自定义回调函数 signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base); if (!...