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. height not divisible by 2

    height not divisible by 2 h.264 - FFMPEG (libx264) "height not divisible by 2" - Stack Ove ...

  2. node.js 在函数内获取当前函数

    js 如何在函数体内部知道 自己在哪个函数内运行呢? 打比方: function a() { // 我想在这里知道我的函数名a和函数function a () {...} } 使用Error的调用栈可 ...

  3. MFC中SliderCtrl控件的使用

    在MFC中滑动条(CSliderCtrl)是个经常使用的控件,使用方法例如以下: 主要要方法有: 1.设置.取得滑动范围: void SetRange( int nMin, int nMax, BOO ...

  4. git 配置代理

    1.目的:配置proxy,使得git可以克隆github上的代码 2.方法:执行下面三条命令,配置下git的代理 git config --global https.proxy https://w00 ...

  5. 【推荐】微服务分布式企业框架Springmvc+mybatis+shiro+Dubbo+ZooKeeper+Redis

              摘要: 主要定位于互联网企业架构,已内置企业信息化系统的基础功能和高效的代码生成工具,包括:系统权限组件.数据权限组件.数据字典组件.核心工具 组件.视图操作组件.工作流组件.代码 ...

  6. python-----自动解压并删除zip文件

    如何自动解压并删除zip? 如何解压  →  使用内置模块来实现(shutil.unpack_archive) 如何删除zip  →  使用内置模块os来实现(os.remove) 如何监测zip的出 ...

  7. ubuntu/linuxmint更换163源及常用软件PPA源记录

    一.163源使用说明 (具体见:http://mirrors.163.com/,不推荐linuxmint更换源!!!) 以Wily(15.10)为例, 编辑/etc/apt/sources.list文 ...

  8. sql的where条件中包含中文,查询不出来的处理方法

    SELECT  * FROM phonenumber_info where PROVANCE=N'广东' and  CITY=N'中山市'

  9. bzoj 1044: [HAOI2008]木棍分割【二分+dp】

    对于第一问二分然后贪心判断即可 对于第二问,设f[i][j]为已经到j为止砍了i段,转移的话从$$ f[i][j]=\sigema f[k][j-1] (s[j]-s[k-1]<=ans) 这里 ...

  10. Odoo免费开源企业信息化平台助力企业成功

    企业信息化变革之路 信息孤岛的真实由来 打开百度App,看更多图片 左边为当下企业现状,右边为Odoo的整体 企业信息孤岛的严重性,来自于企业的自身高速发展,企业以销售为生命主题围绕着客户会搭建一系列 ...