libevent reference Mannual I
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的更多相关文章
- libevent reference Mannual II--library
FYI: http://www.wangafu.net/~nickm/libevent-book/TOC.html The Libevent Reference Manual: Preliminari ...
- libevent reference Mannual V -- Bufferevents
FYI: http://www.wangafu.net/~nickm/libevent-book/Ref6_bufferevent.html Bufferevents: concepts and ba ...
- 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 ...
- libevent reference Mannual III--working with events
FYI: http://www.wangafu.net/~nickm/libevent-book/TOC.html Working with events Libevent’s basic unit ...
- 以libevent网络库为引:网络通信和多线程
1. windows下编译及使用libevent http://www.cnblogs.com/luxiaoxun/p/3603399.html 2. <<libevent学习资料&g ...
- 轻量级网络库libevent概况
Libevent is a library for writing fast portable nonblocking IO. libevent是一个为编写快速可移植的非阻塞IO程序而设计的. lib ...
- Fast portable non-blocking network programming with Libevent--转
Learning Libevent Chapter 0: About this document Chapter 1: A tiny introduction to asynchronous IO. ...
- [2017.02.07] Lua入门学习记录
#!/home/auss/Projects/Qt/annotated/lua -- 这是第一次系统学习Lua语言 --[[ 参考资料: 1. [Lua简明教程](http://coolshell.cn ...
- CUDA中多维数组以及多维纹理内存的使用
纹理存储器(texture memory)是一种只读存储器,由GPU用于纹理渲染的图形专用单元发展而来,因此也提供了一些特殊功能.纹理存储器中的数据位于显存,但可以通过纹理缓存加速读取.在纹理存储器中 ...
随机推荐
- 多台Mac电脑使用同一个apple开发者账号测试
因为公司有苹果一体机,家里有macbook和黑苹果台式机,多台电脑用同一个开发者账号,每次真机调试时都是选择直接reset,回到另外一台电脑,又要重新设置,太麻烦了.直到最近才设置三台电脑都可以,分享 ...
- Python: PS 滤镜--万花筒效果
本文用 Python 实现 PS 的一种滤镜效果,称为万花筒.也是对图像做各种扭曲变换,最后图像呈现的效果就像从万花筒中看到的一样: 图像的效果可以参考之前的博客: http://blog.csdn. ...
- ElasticSearch NEST
1. 什么是ElasticSearch? ElasticSearch is a powerful open source search and analytics engine that makes ...
- /bin/bash: jar: command not found(转载)
转自:http://blog.csdn.net/zhangdaiscott/article/details/23138023 /bin/bash: jar: command not found 解决办 ...
- P4161 [SCOI2009]游戏
传送门 首先这题的本质就是把\(n\)分成若干个数的和,求他们的\(lcm\)有多少种情况 然后据说有这么个结论:若\(p_1^{c_1}+p_2^{c_2}+...+p_m^{c_m}\leq n\ ...
- sublime text2 配置php本地环境时遇到的错误。
首先,将PHP加到电脑的环境变量中如图(D:\PHPEnv\PHP5是我PHP的安装目录): 第二步:添加编译系统配置 第三步:配置详情: { "cmd": ["php. ...
- JavaScript编程艺术-第7章代码汇总(2)
[7.4节] 重回“JavaScript美术馆”代码 ***亲测可用*** HTML: JS:
- hdu5926Mr. Frog’s Game
Mr. Frog's Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 构造 Codeforces Round #107 (Div. 2) B. Phone Numbers
题目传送门 /* 构造:结构体排个序,写的有些啰嗦,主要想用用流,少些了判断条件WA好几次:( */ #include <cstdio> #include <algorithm> ...
- Android ListView动态刷新某项Item
使用ViewHolder来刷新某项数据,而不用每次都全部刷新数据. 继承BaseAdapter,新建ViewHolder类. public class TestListAdapter extends ...