Libevent教程001: 简介与配置 (3)

这就是回调函数的一个生动的例子, 回调函数机制中有了一个调用结果监控方, 就是秘书, 这个角色承担着非常重要的职责: 即是在函数返回结果之后, 调用对应的回调函数. 回调机制一般都实现在异步调用框架之中, 对于写代码的人来说是透明的, 它简化了调用方的职责与智力负担, 一定程度上抽象了代码逻辑, 简化了编程模型(注意: 是一定程度上!). 有了回调机制:

调用方不必再去关心函数返回结果以及返回时机. 不必通过轮询或其它方式去检查异步函数是否返回了结果.

调用方在调用时就向调用结果监控方注册合适的回调, 在调用函数那一刻, 将后续业务逻辑写在回调函数中, 只负责调用就行了. 代码越写越像状态机.

不过正所谓回调一时爽, 调试火葬厂. 写过JavaScript的同学对这一点一定是深有体会. 当程序不能正确运行的时候, 调试很蛋疼. 异步框架本身由于函数返回时机不确定, 调试就比较蛋疼, 再加上回调机制, 那真是火葬厂了. 特别是回调嵌套回调, 里面套个七八层的时候, 那真是把图灵从坟里挖出来也没用的绝望场景.

2. 异步IO与多路复用技术

我们先来看一段经典的同步且阻塞的HTTP客户端程序:

#include <netinet/in.h> // for socketaddr_in #include <sys/socket.h> // for socket functions #include <netdb.h> // for gethostbyname #include <sys/errno.h> // for errno #include <unistd.h> #include <string.h> #include <stdio.h> int main(int argc, char ** argv) { const char query[] = "GET / HTTP/1.0\r\n" "Host: \r\n" "\r\n"; const char hostname[] = "www.baidu.com"; struct sockaddr_in sin; struct hostent * h; const char * cp; int fd; ssize_t n_written, remaining; char buf[4096]; /* * Look up the IP address for the hostname. * Watch out; this isn't threadsafe on most platforms. */ h = gethostbyname(hostname); if(!h) { fprintf(stderr, "E: gethostbyname(%s) failed. ErrMsg: %s\n", hostname, hstrerror(h_errno)); return -__LINE__; } if(h->h_addrtype != AF_INET) { fprintf(stderr, "E: gethostbyname(%s) returned an non AF_INET address.\n", hostname); return -__LINE__; } /* * Allocate a new socket */ fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) { fprintf(stderr, "E: socket failed: %s\n", strerror(errno)); return -__LINE__; } /* * Connect to the remote host */ sin.sin_family = AF_INET; sin.sin_port = htons(80); sin.sin_addr = *((struct in_addr *)(h->h_addr)); if(connect(fd, (struct sockaddr *)(&sin), sizeof(sin)) != 0) { fprintf(stderr, "E: connect to %s failed: %s\n", hostname, strerror(errno)); close(fd); return -__LINE__; } /* * Write the query * XXX Can send succeed partially? */ cp = query; remaining = strlen(query); while(remaining) { n_written = send(fd, cp, remaining, 0); if(n_written < 0) { fprintf(stderr, "E: send failed: %s\n", strerror(errno)); close(fd); return -__LINE__; } remaining -= n_written; cp += n_written; } /* * Get an answer back */ while(1) { ssize_t result = recv(fd, buf, sizeof(buf), 0); if(result == 0) { break; } else if(result < 0) { fprintf(stderr, "recv failed: %s\n", strerror(errno)); close(fd); return -__LINE__; } fwrite(buf, 1, result, stdout); } close(fd); return 0; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygffd.html