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. Binary safe

    https://en.wikipedia.org/wiki/Binary-safe A binary-safe function is one that treats its input as a r ...

  2. YTU 2639: 改错题:类中私有成员的访问

    2639: 改错题:类中私有成员的访问 时间限制: 1 Sec  内存限制: 128 MB 提交: 431  解决: 297 题目描述 /* 改错题: 设计一个日期类和时间类,并编写全局函数displ ...

  3. 韩顺平Oracle笔记

    韩顺平Oracle笔记 分类: DataBase2011-09-07 10:24 3009人阅读 评论(0) 收藏 举报 oracle数据库sqljdbcsystemstring   目录(?)[-] ...

  4. hdoj--1379--DNA Sorting(排序水题)

     DNA Sorting Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  5. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理-转载

    内容是摘抄的,不知最初的原作者,见谅 Java 动态代理.具体有如下四步骤: 通过实现 InvocationHandler 接口创建自己的调用处理器: 通过为 Proxy 类指定 ClassLoade ...

  6. 矩阵取数游戏 2007年NOIP全国联赛提高组(dp+高精)

    矩阵取数游戏 2007年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description [问题描述]帅帅经常跟 ...

  7. 洛谷P4158 [SCOI2009]粉刷匠

    传送门 设$dp[i][j][k][0/1]$表示在涂点$(i,j)$,涂了$k$次,当前点的颜色是否对,最多能刷对多少个格子 首先换行的时候肯定得多刷一次 然后是如果和前一个格子颜色相同,那么当前点 ...

  8. 1051 复数乘法(C#)

    一.题目内容如下: 复数可以写成 ( 的常规形式,其中 A 是实部,B 是虚部,i 是虚数单位,满足 1:也可以写成极坐标下的指数形式 (,其中 R 是复数模,P 是辐角,i 是虚数单位,其等价于三角 ...

  9. CSS 样式的优先级小结

    1. 同一元素引用了多个样式时,排在后面的样式属性的优先级高 例如,下面的 div,同时引用了 [.default] 和 [.user] 中的样式,其中 [.user] 样式中的 width 属性会替 ...

  10. 383 Ransom Note 赎金信

    给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成.如果可以构成,返回 true :否则返回 ...