-
Notifications
You must be signed in to change notification settings - Fork 231
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial checkin for libevent book; mostly example code.
- Loading branch information
0 parents
commit 6c551c0
Showing
9 changed files
with
959 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
|
||
About this document | ||
------------------- | ||
|
||
This document will teach you how to use Libevent 2.0 to write fast | ||
portable asynchronous network IO programs in C. We assume: | ||
|
||
* That you already know C. | ||
* That you already know the basic C networking calls (socket(), | ||
connect(), and so on). | ||
|
||
|
||
A note on examples | ||
------------------ | ||
|
||
The examples here above should work all right on Linux, FreeBSD, | ||
OpenBSD, NetBSD, Mac OS X, Solaris, Android, | ||
|
||
You might notice that some of the examples above | ||
don't compile so well on winows. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
|
||
A tiny introduction to asynchronous I/O | ||
---------------------------------------- | ||
|
||
Most beginning programmers start with synchronous, blocking I/O calls. | ||
An I/O call is _synchronous_ if, when you call it, it does not return | ||
unless and until the operation is completed. When you call | ||
"connect()" on a TCP connection, for example, your operating system | ||
queues a SYN packet to the host on the other side of the TCP | ||
connection, and does not return control back to your application until | ||
it receives a SYN ACK packet from the opposite host, or until enough | ||
time has passed that it decides to give up. | ||
|
||
Here's an example of a really simple syncronous client that writes | ||
|
||
[source,C] | ||
~~~~~~~ | ||
include::01_sync_webclient.c[] | ||
~~~~~~~ | ||
|
||
As you'll see, | ||
|
||
|
||
|
||
|
||
Windows digression: what about overlapped IO? | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
Oh gods no. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
|
||
GENERATED_HTML=01_intro.html | ||
|
||
all: html examples | ||
|
||
html: $(GENERATED_HTML) | ||
|
||
examples: | ||
cd examples_01 && $(MAKE) | ||
|
||
01_intro.html: examples_01/01_sync_webclient.c | ||
|
||
.txt.html: | ||
asciidoc $< | ||
clean: | ||
rm -f *~ | ||
rm -f *.o | ||
rm -f $(GENERATED_HTML) | ||
cd examples_01 && $(MAKE) clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/* For sockaddr_in */ | ||
#include <netinet/in.h> | ||
/* For socket functions */ | ||
#include <sys/socket.h> | ||
/* For fcntl */ | ||
#include <fcntl.h> | ||
|
||
#include <event2/event.h> | ||
#include <event2/buffer.h> | ||
#include <event2/bufferevent.h> | ||
|
||
#include <assert.h> | ||
#include <unistd.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <errno.h> | ||
|
||
void do_read(evutil_socket_t fd, short events, void *arg); | ||
void do_write(evutil_socket_t fd, short events, void *arg); | ||
|
||
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 + 13; | ||
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) | ||
return c - 13; | ||
else | ||
return c; | ||
} | ||
|
||
void | ||
readcb(struct bufferevent *bev, void *ctx) | ||
{ | ||
struct evbuffer *input, *output; | ||
char *line; | ||
size_t n; | ||
input = bufferevent_get_input(bev); | ||
output = bufferevent_get_output(bev); | ||
|
||
while ((line = evbuffer_readln(input, &n, EVBUFFER_EOL_LF))) { | ||
int i; | ||
for (i = 0; i < n; ++i) | ||
line[i] = rot13_char(line[i]); | ||
evbuffer_add(output, line, n); | ||
evbuffer_add(output, "\n", 1); | ||
} | ||
} | ||
|
||
void | ||
errorcb(struct bufferevent *bev, short error, void *ctx) | ||
{ | ||
bufferevent_free(bev); | ||
} | ||
|
||
void | ||
do_accept(evutil_socket_t listener, short event, void *arg) | ||
{ | ||
struct event_base *base = arg; | ||
struct sockaddr_storage ss; | ||
socklen_t slen = sizeof(ss); | ||
int fd = accept(listener, (struct sockaddr*)&ss, &slen); | ||
if (fd < 0) { | ||
perror("accept"); | ||
} else if (fd > FD_SETSIZE) { | ||
close(fd); | ||
} else { | ||
struct bufferevent *bev; | ||
evutil_make_socket_nonblocking(fd); | ||
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); | ||
bufferevent_setcb(bev, readcb, NULL, errorcb, NULL); | ||
bufferevent_enable(bev, EV_READ|EV_WRITE); | ||
} | ||
} | ||
|
||
void | ||
run(void) | ||
{ | ||
evutil_socket_t listener; | ||
struct sockaddr_in sin; | ||
struct event_base *base; | ||
struct event *listener_event; | ||
|
||
base = event_base_new(); | ||
if (!base) | ||
return; /*XXXerr*/ | ||
|
||
sin.sin_family = AF_INET; | ||
sin.sin_addr.s_addr = 0; | ||
sin.sin_port = htons(40713); | ||
|
||
listener = socket(AF_INET, SOCK_STREAM, 0); | ||
evutil_make_socket_nonblocking(listener); | ||
|
||
#ifndef WIN32 | ||
{ | ||
int one = 1; | ||
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); | ||
} | ||
#endif | ||
|
||
if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) { | ||
perror("bind"); | ||
return; | ||
} | ||
|
||
if (listen(listener, 16)<0) { | ||
perror("listen"); | ||
return; | ||
} | ||
|
||
listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base); | ||
/*XXX check it */ | ||
event_add(listener_event, NULL); | ||
|
||
event_base_dispatch(base); | ||
} | ||
|
||
int | ||
main(int c, char **v) | ||
{ | ||
setvbuf(stdout, NULL, _IONBF, 0); | ||
|
||
run(); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* 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> | ||
|
||
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 + 13; | ||
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) | ||
return c - 13; | ||
else | ||
return c; | ||
} | ||
|
||
void | ||
child(int fd) | ||
{ | ||
char *outbuf; | ||
size_t outbuf_len = 1024; | ||
size_t outbuf_used = 0; | ||
ssize_t result; | ||
|
||
outbuf = malloc(outbuf_len); | ||
if (!outbuf) { | ||
perror("malloc"); | ||
exit(1); | ||
} | ||
|
||
while (1) { | ||
char ch; | ||
result = recv(fd, &ch, 1, 0); | ||
if (result == 0) { | ||
break; | ||
} else if (result == -1) { | ||
perror("read"); | ||
break; | ||
} | ||
|
||
if (outbuf_used == outbuf_len) { | ||
char *outbuf2 = realloc(outbuf, outbuf_len*2); | ||
if (outbuf2 == NULL) { | ||
perror("realloc"); | ||
break; | ||
} | ||
outbuf = outbuf2; | ||
outbuf_len *= 2; | ||
} | ||
|
||
outbuf[outbuf_used++] = rot13_char(ch); | ||
|
||
if (ch == '\n') { | ||
send(fd, outbuf, outbuf_used, 0); | ||
outbuf_used = 0; | ||
continue; | ||
} | ||
} | ||
|
||
free(outbuf); | ||
} | ||
|
||
void | ||
run(void) | ||
{ | ||
int listener; | ||
struct sockaddr_in sin; | ||
|
||
sin.sin_family = AF_INET; | ||
sin.sin_addr.s_addr = 0; | ||
sin.sin_port = htons(40713); | ||
|
||
listener = socket(AF_INET, SOCK_STREAM, 0); | ||
|
||
#ifndef WIN32 | ||
{ | ||
int one = 1; | ||
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); | ||
} | ||
#endif | ||
|
||
if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) { | ||
perror("bind"); | ||
return; | ||
} | ||
|
||
if (listen(listener, 16)<0) { | ||
perror("listen"); | ||
return; | ||
} | ||
|
||
|
||
|
||
while (1) { | ||
struct sockaddr_storage ss; | ||
socklen_t slen = sizeof(ss); | ||
int fd = accept(listener, (struct sockaddr*)&ss, &slen); | ||
if (fd < 0) { | ||
perror("accept"); | ||
} else { | ||
if (fork() == 0) { | ||
child(fd); | ||
exit(0); | ||
} | ||
} | ||
} | ||
} | ||
|
||
int | ||
main(int c, char **v) | ||
{ | ||
run(); | ||
return 0; | ||
} |
Oops, something went wrong.