Example of the use method for the libevent library
- 2020-04-02 02:04:43
- OfStack
Then write a very simple Time Server example: when you connect to the Server end directly provides the Time, and then ends the connection. Event_init () represents the variable used to initialize the libevent. Event_set (&ev, s, EV_READ | EV_PERSIST, connection_accept, &ev) puts the s File Description into ev (the first parameter and the second parameter) and tells it to call connection_accept() (the fourth parameter) when the event (EV_READ of the third parameter) occurs, dropping ev as an argument (the fifth parameter). The EV_PERSIST message says do not remove the event when the call goes in (keep it in the event Queue), which can be compared to the code that registers connection_time() inside connection_accept(). Event_add (&ev, NULL) registers the ev in the event queue, and the second parameter specifies a Timeout time, which is set to NULL to ignore.
Note: this code comes from the network and is crude, but the usage of libevent is clear.
Attached to the source code:
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <event.h>
#include <stdio.h>
#include <time.h>
void connection_time(int fd, short event, struct event *arg)
{
char buf[32];
struct tm t;
time_t now;
time(&now);
localtime_r(&now, &t);
asctime_r(&t, buf);
write(fd, buf, strlen(buf));
shutdown(fd, SHUT_RDWR);
free(arg);
}
void connection_accept(int fd, short event, void *arg)
{
fprintf(stderr, "%s(): fd = %d, event = %d.n", __func__, fd, event);
struct sockaddr_in s_in;
socklen_t len = sizeof(s_in);
int ns = accept(fd, (struct sockaddr *) &s_in, &len);
if (ns < 0) {
perror("accept");
return;
}
struct event *ev = malloc(sizeof(struct event));
event_set(ev, ns, EV_WRITE, (void *) connection_time, ev);
event_add(ev, NULL);
}
int main(void)
{
int s = socket(PF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("socket");
exit(1);
}
struct sockaddr_in s_in;
bzero(&s_in, sizeof(s_in));
s_in.sin_family = AF_INET;
s_in.sin_port = htons(7000);
s_in.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr *) &s_in, sizeof(s_in)) < 0) {
perror("bind");
exit(1);
}
if (listen(s, 5) < 0) {
perror("listen");
exit(1);
}
event_init();
struct event ev;
event_set(&ev, s, EV_READ | EV_PERSIST, connection_accept, &ev);
event_add(&ev, NULL);
event_dispatch();
return 0;
}
Writing a Nonblocking Network Program usually deals with Buffering, but it's not easy to write, mainly because read() or recv() doesn't guarantee you can read a line at a time.
A fairly good Buffer Library can be used in libevent. The full description can be seen in man event. The most commonly used functions are evbuffer_add() and evbuffer_readline().
The following directly provides libevent-buff. C as an example, after the compilation to see the execution results, then look back to the source code should have a feeling:
#include <sys/time.h>
#include <event.h>
#include <stdio.h>
void printbuf(struct evbuffer *evbuf)
{
for (;;) {
char *buf = evbuffer_readline(evbuf);
printf("* buf = %p, the string = "e[1;33m%se[m"n", buf, buf);
if (buf == NULL)
break;
free(buf);
}
}
int main(void)
{
struct evbuffer *evbuf;
evbuf = evbuffer_new();
if (evbuf == NULL) {
fprintf(stderr, "%s(): evbuffer_new() failed.n", __func__);
exit(1);
}
u_char *buf1 = "gslin";
printf("* Add "e[1;33m%se[m".n", buf1);
evbuffer_add(evbuf, buf1, strlen(buf1));
printbuf(evbuf);
u_char *buf2 = " is reading.nAnd he is at home.nLast.";
printf("* Add "e[1;33m%se[m".n", buf2);
evbuffer_add(evbuf, buf2, strlen(buf2));
printbuf(evbuf);
evbuffer_free(evbuf);
}
The last event_dispatch() indicates an event loop, which is executed as a callback function when an event occurs on any of the File Description in the Queue.