参考文章
可以用上篇文章的poll client进行测试
bufferevent 帮我们更好的处理单纯的读写操作
evconnlistener_new_bind内部帮我们使用了socket的accept bind等函数
带有定时器超过时间没有读写操作就将断开连接。
bufferevent_set_timeouts
#include <iostream>
#include <curl/curl.h>
#include <assert.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <event2/thread.h>
#include <sys/types.h>
#include <error.h>
#include <unistd.h>
#include <string.h>
void event_cb(struct bufferevent* bev, short event, void * arg )
{
if ( event & BEV_EVENT_TIMEOUT )
printf("client timeout\n");
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 socket_read_cb(struct bufferevent* bev, void *arg)
{
char msg[4096];
size_t len = bufferevent_read(bev,msg,sizeof(msg));
msg[len] = '\0';
printf("recv the client msg: %s\n",msg);
char reply_msg[4096] = " received the msg : ";
strcat(reply_msg+ strlen(reply_msg),msg);
bufferevent_write(bev,reply_msg, strlen(reply_msg));
}
void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr*sock, int socklen, void*arg)
{
printf("accapt a client %d \n",fd);
struct event_base* base = (struct event_base *)arg;
struct bufferevent *bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev,socket_read_cb,NULL,event_cb,NULL);
bufferevent_enable(bev,EV_READ | EV_PERSIST);
struct timeval tv = {10,0};
bufferevent_set_timeouts (bev, &tv, 0);
}
typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{
int errno_save;
evutil_socket_t listener;
listener = ::socket(AF_INET, SOCK_STREAM, 0);
if( listener == -1 )
return -1;
//允许多次绑定同一个地址。要用在socket和bind之间
evutil_make_listen_socket_reuseable(listener);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port);
if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
goto error;
if( ::listen(listener, listen_num) < 0)
goto error;
//跨平台统一接口,将套接字设置为非阻塞状态
evutil_make_socket_nonblocking(listener);
return listener;
error:
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save;
return -1;
}
void cmd_msg_cb(int fd, short events, void* arg)
{
char msg[1024];
int ret = read(fd, msg, sizeof(msg));
if( ret <= 0 )
{
perror("read fail ");
exit(1);
}
int sockfd = *((int*)arg);
//把终端的消息发送给服务器端
//为了简单起见,不考虑写一半数据的情况
write(sockfd, msg, ret);
}
void socket_read_cb(int fd , short events , void * arg )
{
char msg[4096];
int len = read(fd, msg, sizeof(msg) - 1);
if(len <= 0)
{
printf("some error happen when read\n");
return;
}
msg[len] = '\0';
printf("recv the client msg : %s\n", msg);
}
void accept_cb(int fd , short events , void * arg )
{
evutil_socket_t sockfd;
struct sockaddr_in client;
socklen_t len = sizeof(client);
sockfd = ::accept(fd, (struct sockaddr*)&client, &len);
evutil_make_socket_nonblocking(sockfd);
printf("accept a client %d\n", sockfd);
struct event_base* base = (event_base*)arg;
/*
* 很堵,被STDIN堵住了
//动态创建一个event结构体,并将其作为回调参数传递给
struct event* ev2 = event_new(NULL, -1, 0, NULL, NULL);
struct event* ev = event_new(NULL, -1, 0, NULL, NULL);
event_assign(ev2, base, STDIN_FILENO, EV_WRITE | EV_PERSIST, cmd_msg_cb, (void *)&sockfd);
event_assign(ev, base, sockfd, EV_READ | EV_PERSIST, socket_read_cb, NULL);
event_add(ev, NULL);
event_add(ev2,NULL);
*/
struct bufferevent* bev = bufferevent_socket_new(base,sockfd,BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev,socket_read_cb,NULL, event_cb,arg);
bufferevent_enable(bev,EV_READ );
}
int main() {
/*
int listener = tcp_server_init(5000,10);
assert(listener != -1 );
struct event_base *base = event_base_new();
assert(base != NULL);
//creatfifo((void*)base);
struct event* listen_event;
listen_event = event_new(base,listener,EV_READ|EV_WRITE|EV_PERSIST,accept_cb,(void*)base);
*/
struct sockaddr_in sin ;
memset(&sin,0,sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(5000);
struct event_base *base = event_base_new();
struct evconnlistener * listener = evconnlistener_new_bind(base,listener_cb,base,
LEV_OPT_CLOSE_ON_FREE, 10,
(struct sockaddr *)&sin, sizeof(struct sockaddr_in));
//监听终端输入事件
event_base_dispatch(base);
evconnlistener_free(listener);
event_base_free(base);
return 0;
}