FYI:http://www.wangafu.net/~nickm/libevent-book/

This lib is a integral of asynchronous IO. we should change the concept from blocking PRO to nonblocking PRO.

Example: A simple blocking HTTP client

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

All the network calls are in the code above are blocking, gethostbyname, connect, recv, send. This makes the code cannot work effectively. To work with multiple IO, please see following code with fork()

Example: Forking ROT13 server:

 /* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h> #include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h> #define MAX_LINE 16384 char
rot13_char(char c)
{
/* We don't want to use isalpha here; setting the locale would change
* which characters are considered alphabetical. */
if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
return c + ;
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
return c - ;
else
return c;
} void
child(int fd)
{
char outbuf[MAX_LINE+];
size_t outbuf_used = ;
ssize_t result; while () {
char ch;
result = recv(fd, &ch, , );
if (result == ) {
break;
} else if (result == -) {
perror("read");
break;
} /* We do this test to keep the user from overflowing the buffer. */
if (outbuf_used < sizeof(outbuf)) {
outbuf[outbuf_used++] = rot13_char(ch);
} if (ch == '\n') {
send(fd, outbuf, outbuf_used, );
outbuf_used = ;
continue;
}
}
} void
run(void)
{
int listener;
struct sockaddr_in sin; sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ;
sin.sin_port = htons(); listener = socket(AF_INET, SOCK_STREAM, ); #ifndef WIN32
{
int one = ;
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
}
#endif if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < ) {
perror("bind");
return;
} if (listen(listener, )<) {
perror("listen");
return;
} while () {
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
int fd = accept(listener, (struct sockaddr*)&ss, &slen);
if (fd < ) {
perror("accept");
} else {
if (fork() == ) {
child(fd);
exit();
}
}
}
} int
main(int c, char **v)
{
run();
return ;
}

Perfect? Not quite. Process creation (and even thread creation) can be pretty expensive on some platforms. A thread pool is the answer to having multiple connections.

First, set sockets nonblocking.  Call

fcntl(fd, F_SETFL, O_NONBLOCK);

Once nonblocking is set to fd (the socket), return of the fd call is complete the operation immediately or a special error code.

For example:

 /* This will work, but the performance will be unforgivably bad. */
int i, n;
char buf[];
for (i=; i < n_sockets; ++i)
fcntl(fd[i], F_SETFL, O_NONBLOCK); while (i_still_want_to_read()) {
for (i=; i < n_sockets; ++i) {
n = recv(fd[i], buf, sizeof(buf), );
if (n == ) {
handle_close(fd[i]);
} else if (n < ) {
if (errno == EAGAIN)
; /* The kernel didn't have any data for us to read. */
else
handle_error(fd[i], errno);
} else {
handle_input(fd[i], buf, n);
}
}
}

Using nonblocking sockets, the code would work, but only barely. The performance will be awful, for two reasons.

  • First, when there is no data to read on either connection the loop will spin indefinitely, using up all your CPU cycles.
  • Second, the delay is proportional to the number of users.

So what we need is a way to tell the kernel "wait until one of these sockets is ready to give me some data, and tell me which ones are ready."

The oldest solution that people still use for this problem is select(). Here’s a reimplementation of our ROT13 server, using select() this time.

Example: select()-based ROT13 server

 /* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For fcntl */
#include <fcntl.h>
/* for select */
#include <sys/select.h> #include <assert.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h> #define MAX_LINE 16384 char
rot13_char(char c)
{
/* We don't want to use isalpha here; setting the locale would change
* which characters are considered alphabetical. */
if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
return c + ;
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
return c - ;
else
return c;
} struct fd_state {
char buffer[MAX_LINE];
size_t buffer_used; int writing;
size_t n_written;
size_t write_upto;
}; struct fd_state *
alloc_fd_state(void)
{
struct fd_state *state = malloc(sizeof(struct fd_state));
if (!state)
return NULL;
state->buffer_used = state->n_written = state->writing =
state->write_upto = ;
return state;
} void
free_fd_state(struct fd_state *state)
{
free(state);
} void
make_nonblocking(int fd)
{
fcntl(fd, F_SETFL, O_NONBLOCK);
} int
do_read(int fd, struct fd_state *state)
{
char buf[];
int i;
ssize_t result;
while () {
result = recv(fd, buf, sizeof(buf), );
if (result <= )
break; for (i=; i < result; ++i) {
if (state->buffer_used < sizeof(state->buffer))
state->buffer[state->buffer_used++] = rot13_char(buf[i]);
if (buf[i] == '\n') {
state->writing = ;
state->write_upto = state->buffer_used;
}
}
} if (result == ) {
return ;
} else if (result < ) {
if (errno == EAGAIN)
return ;
return -;
} return ;
} int
do_write(int fd, struct fd_state *state)
{
while (state->n_written < state->write_upto) {
ssize_t result = send(fd, state->buffer + state->n_written,
state->write_upto - state->n_written, );
if (result < ) {
if (errno == EAGAIN)
return ;
return -;
}
assert(result != ); state->n_written += result;
} if (state->n_written == state->buffer_used)
state->n_written = state->write_upto = state->buffer_used = ; state->writing = ; return ;
} void
run(void)
{
int listener;
struct fd_state *state[FD_SETSIZE];
struct sockaddr_in sin;
int i, maxfd;
fd_set readset, writeset, exset; sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ;
sin.sin_port = htons(); for (i = ; i < FD_SETSIZE; ++i)
state[i] = NULL; listener = socket(AF_INET, SOCK_STREAM, );
make_nonblocking(listener); #ifndef WIN32
{
int one = ;
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
}
#endif if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < ) {
perror("bind");
return;
} if (listen(listener, )<) {
perror("listen");
return;
} FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exset); while () {
maxfd = listener; FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exset); FD_SET(listener, &readset); for (i=; i < FD_SETSIZE; ++i) {
if (state[i]) {
if (i > maxfd)
maxfd = i;
FD_SET(i, &readset);
if (state[i]->writing) {
FD_SET(i, &writeset);
}
}
} if (select(maxfd+, &readset, &writeset, &exset, NULL) < ) {
perror("select");
return;
} if (FD_ISSET(listener, &readset)) {
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
int fd = accept(listener, (struct sockaddr*)&ss, &slen);
if (fd < ) {
perror("accept");
} else if (fd > FD_SETSIZE) {
close(fd);
} else {
make_nonblocking(fd);
state[fd] = alloc_fd_state();
assert(state[fd]);/*XXX*/
}
} for (i=; i < maxfd+; ++i) {
int r = ;
if (i == listener)
continue; if (FD_ISSET(i, &readset)) {
r = do_read(i, state[i]);
}
if (r == && FD_ISSET(i, &writeset)) {
r = do_write(i, state[i]);
}
if (r) {
free_fd_state(state[i]);
state[i] = NULL;
close(i);
}
}
}
} int
main(int c, char **v)
{
setvbuf(stdout, NULL, _IONBF, ); run();
return ;
}

Problem: generating and reading the select() bit arrays takes time proportional to the largest fd that you provided for select(), the select() call scales terribly when the number of sockets is high.

Solution: diversity repalcement functions are comming out in different operating systems.  Unfortunately, none of the efficient interfaces is a ubiquitous standard.

Linux: epoll(),

BSDs (including Darwin): kqueue(),

Solaris: evports and /dev/poll…

Libevent API is an abstraction that wraps all of these interfaces, and provides whichever one of them is the most efficient.

libevent reference Mannual I的更多相关文章

  1. libevent reference Mannual II--library

    FYI: http://www.wangafu.net/~nickm/libevent-book/TOC.html The Libevent Reference Manual: Preliminari ...

  2. libevent reference Mannual V -- Bufferevents

    FYI: http://www.wangafu.net/~nickm/libevent-book/Ref6_bufferevent.html Bufferevents: concepts and ba ...

  3. libevent reference Mannual IV --Helper functions and types

    FYI: http://www.wangafu.net/~nickm/libevent-book/Ref5_evutil.html Helper functions and types for Lib ...

  4. libevent reference Mannual III--working with events

    FYI: http://www.wangafu.net/~nickm/libevent-book/TOC.html Working with events Libevent’s basic unit ...

  5. 以libevent网络库为引:网络通信和多线程

    1. windows下编译及使用libevent  http://www.cnblogs.com/luxiaoxun/p/3603399.html 2.  <<libevent学习资料&g ...

  6. 轻量级网络库libevent概况

    Libevent is a library for writing fast portable nonblocking IO. libevent是一个为编写快速可移植的非阻塞IO程序而设计的. lib ...

  7. Fast portable non-blocking network programming with Libevent--转

    Learning Libevent Chapter 0: About this document Chapter 1: A tiny introduction to asynchronous IO. ...

  8. [2017.02.07] Lua入门学习记录

    #!/home/auss/Projects/Qt/annotated/lua -- 这是第一次系统学习Lua语言 --[[ 参考资料: 1. [Lua简明教程](http://coolshell.cn ...

  9. CUDA中多维数组以及多维纹理内存的使用

    纹理存储器(texture memory)是一种只读存储器,由GPU用于纹理渲染的图形专用单元发展而来,因此也提供了一些特殊功能.纹理存储器中的数据位于显存,但可以通过纹理缓存加速读取.在纹理存储器中 ...

随机推荐

  1. Robot Framework 怎样写好Test Case

    1.介绍 这是一个关于如何用Robot Framework写好Test Case的高层次的指导准则 怎样实际的与系统进行交互不在此文档范围内 最重要的准则是使测试用例尽可能的让熟悉此领域的人觉得简单易 ...

  2. HDU 5773The All-purpose Zero

    The All-purpose Zero Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  3. Spark 多项式逻辑回归__多分类

    package Spark_MLlib import org.apache.spark.ml.Pipeline import org.apache.spark.ml.classification.{B ...

  4. 9. Ext基础1 -- Ext中 getDom、get、getCmp的区别

    转自:https://blog.csdn.net/huobing123456789/article/details/7982061 要学习及应用好Ext框架,必须需要理解Html DOM.Ext El ...

  5. mysql status关键字 数据表设计中慎重使用

    mysql status关键字  数据表设计中慎重使用

  6. (数论 欧拉筛法)51NOD 1106 质数检测

    给出N个正整数,检测每个数是否为质数.如果是,输出"Yes",否则输出"No".   Input 第1行:一个数N,表示正整数的数量.(1 <= N &l ...

  7. 服务器出现 nginx 502 Bad Gateway

    发生原因1.PHP FastCGI进程数不够用 当网站并发访问巨大时,php fastcgi的进程数不有一定的保障,因为cgi是单线程多进程工作的,也就是说cgi需要处理完一个页面后再继续下一个页面. ...

  8. codechef: BINARY, Binary Movements

    非常有毛病的一道题,我一个一个读字符死活过不去,改成整行整行读就 A 了... 做法就是...最小点覆盖... 我们发现可以把一个点向上跳看做被吃掉了,然后最顶层的点是无法向上跳所以不能被吃掉,然后被 ...

  9. webservice 权限控制

    webservice 如何限制访问,权限控制?1.服务器端总是要input消息必须携带用户名.密码信息 如果不用cxf框架,SOAP消息(xml片段)的生成.解析都是有程序员负责 2.拦截器 为了让程 ...

  10. Canvas入门笔记-实现极简画笔

    今天学习了Html5 Canvas入门,已经有大神写得很详细了http://www.cnblogs.com/tim-li/archive/2012/08/06/2580252.html#8 在学习过后 ...