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用于纹理渲染的图形专用单元发展而来,因此也提供了一些特殊功能.纹理存储器中的数据位于显存,但可以通过纹理缓存加速读取.在纹理存储器中 ...
随机推荐
- Robot Framework 怎样写好Test Case
1.介绍 这是一个关于如何用Robot Framework写好Test Case的高层次的指导准则 怎样实际的与系统进行交互不在此文档范围内 最重要的准则是使测试用例尽可能的让熟悉此领域的人觉得简单易 ...
- spring boot-启动及配置文件
spring boot启动: 1:默认启动方法 public static void main(String[] args) { SpringApplication.run(UserServiceAp ...
- [置顶] Silverlight之控件应用总结(一)(3)
[置顶] Silverlight之控件应用总结(一)(3) 分类: 技术2012-04-02 20:35 2442人阅读 评论(1) 收藏 举报 silverlightradiobuttondatat ...
- POJ 3734 Blocks 矩阵递推
POJ3734 比较简单的递推题目,只需要记录当前两种颜色均为偶数, 只有一种颜色为偶数 两种颜色都为奇数 三个数量即可,递推方程相信大家可以导出. 最后来个快速幂加速即可. #include< ...
- bzoj1531
背包+倍增 直接背包跑不过去,那么我们把容量分成二进制,然后原来需要枚举c次就只用枚举log(c)次了,这样还是能组合出任意小于等于c的组合方案 #include<bits/stdc++.h&g ...
- JAVA的引用类型变量(C/C++中叫指针)
任何变量只要存在内存中,就需要有一个唯一的编号标识这个变量在内存中的位置,而这个唯一的内存编号就是内存地址,内存地址就是所谓的指针!
- mysql之distinct
记录一下这几天看mysql必知必会的小知识点: 关于mysql查询不同的行 比如记录表中 查询有多少个城市 可能查出很多城市 可以用distinct 来解决这个问题 SELECT DISTINCT c ...
- Kafka详解与总结(七)-Kafka producer拦截器(interceptor)
1. 拦截器原理 Producer拦截器(interceptor)是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于producer而言,interceptor ...
- 启动VMware环境下的Linux操作系统,添加新分区
启动VMware环境下的Linux操作系统,添加新分区,需要root账号身份. 3.1 [fdisk -l] 最大分区为/dev/sda3,说明新创建的分区将会是sda4 3.2 输入[fdisk / ...
- DFS POJ 1321 棋盘问题
题目传送门 /* DFS:因为一行或一列都只放一个,可以枚举从哪一行开始放,DFS放棋子,同一列只能有一个 */ #include <cstdio> #include <algori ...