(1) echo_server.c
listen_event的callback函数是 do_accept_cb
bev (buffer event)的三个callback函数:read_cb, write_cb, error_cb。 本例中,server端无需write_cb函数
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <assert.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#define LISTEN_PORT 9999
#define LISTEN_BACKLOG 32
#define oops(msg) { perror(msg); exit(EXIT_FAILURE); }
void read_cb(struct bufferevent *bev, void *arg) {
#define MAX_LINE 256
char line[MAX_LINE+1];
int n;
evutil_socket_t fd = bufferevent_getfd(bev);
while (n = bufferevent_read(bev, line, MAX_LINE), n > 0) {
line[n] = '\0';
printf("fd=%u, read line: %s\n", fd, line);
bufferevent_write(bev, line, n);
}
}
void write_cb(struct bufferevent *bev, void *arg) {}
void error_cb(struct bufferevent *bev, short event, void *arg) {
evutil_socket_t fd = bufferevent_getfd(bev);
printf("fd = %u, ", fd);
if (event & BEV_EVENT_TIMEOUT) {
printf("Timed out\n"); //if bufferevent_set_timeouts() called
}
else if (event & BEV_EVENT_EOF) {
printf("connection closed\n");
}
else if (event & BEV_EVENT_ERROR) {
printf("some other error\n");
}
bufferevent_free(bev);
}
void do_accept_cb(evutil_socket_t sockfd, short event_type, void *arg){
evutil_socket_t fd;
struct sockaddr_in sin;
socklen_t slen;
fd = accept(sockfd, (struct sockaddr *)&sin, &slen);
if (fd < 0) oops("ERROR: accept: ");
if (fd > FD_SETSIZE) oops("ERROR: fd > FD_SETSIZE");
printf("ACCEPT: fd = %u\n", fd);
struct event_base *base;
base = (struct event_base *)arg;
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, read_cb, NULL, error_cb, arg);
bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
}
int main(int argc, char **argv){
evutil_socket_t socket_fd;
socket_fd = socket(PF_INET, SOCK_STREAM, 0);
assert(socket_fd > 0);
if(socket_fd == -1) oops("ERROR: socket initiate:");
evutil_make_listen_socket_reuseable(socket_fd);
struct sockaddr_in address;
bzero((void *)&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("172.16.166.129");
// address.sin_addr.s_addr = 0;
address.sin_port = htons(LISTEN_PORT);
int bind_return = bind(socket_fd, (struct sockaddr *)&address, sizeof(address));
if(bind_return == -1) oops("ERROR: bind:");
int listen_return = listen(socket_fd, LISTEN_BACKLOG);
if(listen_return == -1) oops("ERROR: listen:");
//================================================
puts("Listening...");
evutil_make_socket_nonblocking(socket_fd);
struct event_base *base;
struct event *listen_event;
base = event_base_new();
assert(base != NULL);
if(base == NULL) oops("ERROR: event_base_new() :");
listen_event = event_new(base, socket_fd, EV_READ|EV_PERSIST, do_accept_cb, (void*)base);
event_add(listen_event, NULL); //NULL: no timeout
event_base_dispatch(base);
puts("The End.");
return 0;
}
(2) echo_client.c
一个普通的client端,没有用libevent.
改进方法:可以设置buffer_event, 然后实现write_cb函数和error_cb函数。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#define oops(msg) { perror(msg); exit(EXIT_FAILURE); }
#define SIZE 256
#define LISTEN_PORT 9999
int main(){
int socket_fd = socket(PF_INET, SOCK_STREAM, 0);
if(socket_fd == -1) oops("socket initiating error...");
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("172.16.166.129");
// address.sin_addr.s_addr = 0;
address.sin_port = htons(LISTEN_PORT);
int connect_result = connect(socket_fd, (struct sockaddr*)&address, sizeof(address));
if(connect_result == -1) oops("connect error...");
char buffer[] = "hello world";
ssize_t write_length = write(socket_fd, buffer, strlen(buffer)+1); //write to socket_fd
if(write_length != (strlen(buffer)+1)) oops("error: write ...");
ssize_t read_length = read(socket_fd, buffer, strlen(buffer)+1);
if(read_length == -1) oops("error: read data from socket...");
printf("the ret msg is: %s\n", buffer);
close(socket_fd);
return EXIT_SUCCESS;
}
3. Makefile.am
AM_CPPFLAGS = -I/usr/local/include
LDADD = -L/usr/local/lib -levent
bin_PROGRAMS = echo-server echo-client
echo_server_SOURCES = echo_server.c
echo_client_SOURCES = echo_client.c