libevent之C/S代码

服务器代码1

  1. 开启客户端连接服务器:nc 127.0.0.1 8000
  2. 客户端给服务器发送消息,可以看到服务器会回复一样的消息
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>

#define LISTEN_PORT 8000
#define LIATEN_BACKLOG 32

/*********************************************************************************
*                   函数声明
**********************************************************************************/
//accept回调函数
void do_accept_cb(evutil_socket_t listener, short event, void *arg);
//read 回调函数
void read_cb(struct bufferevent *bev, void *arg);
//error回调函数
void error_cb(struct bufferevent *bev, short event, void *arg);
/*                   函数体
**********************************************************************************/
//accept回调函数
void do_accept_cb(evutil_socket_t listener, short event, void *arg)
{
  //传入的event_base指针
  struct event_base *base = (struct event_base*)arg;
  
  struct sockaddr_in sin; //声明地址
  socklen_t slen = sizeof(sin);  //地址长度声明
  
  //接收客户端,并返回新的套接字conn_fd用于通讯
  evutil_socket_t  conn_fd= accept(listener, (struct sockaddr *)&sin, &slen);
  if (conn_fd< 0)
  {
    perror("error accept");
    return;
  }
  printf("new client[%u]  connect success \n", conn_fd);
  
  //使用新的连接套接字conn_fd建立bufferevent,并将bufferevent也安插到base上
  struct bufferevent *bev = bufferevent_socket_new(base, conn_fd, BEV_OPT_CLOSE_ON_FREE);
  bufferevent_setcb(bev, read_cb, NULL, error_cb, arg); //设置回调函数read_cb \ error_cb
  bufferevent_enable(bev, EV_READ | EV_PERSIST);//启用永久read/write
  //bufferevent_enable(bev,EV_WRITE); //默认情况下,EV_WRITE是开启的
}
//read 回调函数
void read_cb(struct bufferevent *bev, void *arg)
{  
  struct evbuffer* input = bufferevent_get_input(bev); //获取读evbuffer的情况
  int n = evbuffer_get_length(input); //获取evbuffer中字节个数

  char buf[1024];
  bufferevent_read(bev,buf,n); //从缓冲区中读走n个字节的数据
  buf[n] = '\0';
  printf("read message = %s",buf);
  
  bufferevent_write(bev,buf,n); //回射信息给client
}
//error回调函数
void error_cb(struct bufferevent *bev, short event, void *arg)
{
  //通过传入参数bev找到socket fd
  evutil_socket_t fd = bufferevent_getfd(bev);
  //cout << "fd = " << fd << endl;
  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);
}
 
int main()
{
  evutil_socket_t listener;
  listener = socket(AF_INET, SOCK_STREAM, 0);
  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(LISTEN_PORT);
  if (bind(listener, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
    perror("bind");
    return 1;
  }
  if (listen(listener, 1000) < 0) {
    perror("listen");
    return 1;
  }
  
  printf("Listening...\n");
  
  evutil_make_socket_nonblocking(listener);
  
  struct event_base *base = event_base_new();
  //监听套接字listener可读事件:一旦有client连接,就会调用do_accept_cb回调函数
  struct event *listen_event = event_new(base, listener, EV_READ | EV_PERSIST, do_accept_cb, (void*)base);

  event_add(listen_event, NULL);
  event_base_dispatch(base);

  return 0;
}

服务器代码2

此代码是修改了hello-world.c

#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#ifndef WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif

#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>



static const int PORT = 8000;

static void listener_cb(struct evconnlistener *, evutil_socket_t,struct sockaddr *, int socklen, void *);
static void conn_readcb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);

int main(int argc, char **argv)
{
	struct event_base *base;
	struct evconnlistener *listener;
	struct event *signal_event;

	struct sockaddr_in sin;
#ifdef WIN32
	WSADATA wsa_data;
	WSAStartup(0x0201, &wsa_data);
#endif

	base = event_base_new();
	if (!base) {
		fprintf(stderr, "Could not initialize libevent!\n");
		return 1;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);

	listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
	    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
	    (struct sockaddr*)&sin,
	    sizeof(sin));

	if (!listener) {
		fprintf(stderr, "Could not create a listener!\n");
		return 1;
	}

	signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);

	if (!signal_event || event_add(signal_event, NULL)<0) {
		fprintf(stderr, "Could not create/add a signal event!\n");
		return 1;
	}

	event_base_dispatch(base);

	evconnlistener_free(listener);
	event_free(signal_event);
	event_base_free(base);

	printf("done\n");
	return 0;
}

static void
listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data)
{
	struct event_base *base = (struct event_base*)user_data;
	struct bufferevent *bev;

	bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	if (!bev) {
		fprintf(stderr, "Error constructing bufferevent!");
		event_base_loopbreak(base);
		return;
	}
	bufferevent_setcb(bev, conn_readcb, NULL, conn_eventcb, NULL);
	bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
}

static void
conn_readcb(struct bufferevent *bev, void *user_data)
{
	struct evbuffer *input = bufferevent_get_input(bev);

  int size = evbuffer_get_length(input);
  if(size > 0)
  {
    char buf[1024];
    bufferevent_read(bev,buf,size);
    printf("read = %s",buf);

    bufferevent_write(bev,buf,size);
    memset(buf,0,sizeof(buf));
  }
}

static void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
	if (events & BEV_EVENT_EOF) 
  {
		printf("Connection closed.\n");
	} 
  else if (events & BEV_EVENT_ERROR) 
  {
    printf("Got an error on the connection: %s\n",strerror(errno));
	}

	bufferevent_free(bev);
}

static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{
	struct event_base *base = (struct event_base*)user_data;
	struct timeval delay = { 2, 0 };

	printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

	event_base_loopexit(base, &delay);
}

客户端代码1

说明:效果和使用nc 127.0.0.1 8000开启的客户端一样
代码详解:
1.STDIN标准输入,使用event_new事件监控
2.连接到服务器的套接字sock_fd,使用bufferevent_sock_new监控

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#ifndef WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif

#include <netinet/tcp.h>
#include <unistd.h>

#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>

static const int PORT = 8000;

#define BUFFER_MAX_SIZE 1024

static void read_cb(struct bufferevent *bev, void *arg)
{
  char recvbuf[BUFFER_MAX_SIZE] = {'\0'};
  struct evbuffer* input = bufferevent_get_input(bev);
  int n = evbuffer_get_length(input);
  
  bufferevent_read(bev,recvbuf,n);
  recvbuf[n]='\0';
  printf("recv = %s\n",recvbuf);
}

static void event_cb(struct bufferevent *bev, short events, void *arg)
{
	if (events & BEV_EVENT_EOF) 
  {
		printf("Connection closed.\n");
	} 
  else if (events & BEV_EVENT_ERROR) 
  {
    printf("Got an error on the connection: %s\n",strerror(errno));
	}
  else if (events & BEV_EVENT_CONNECTED)
  {
    printf("client has connect server successfully...\n");
    return;
  }

  struct event* ev_stdin = (struct event*)arg;
  event_free(ev_stdin);
	bufferevent_free(bev);
}

void stdin_cb(int fd, short events, void *arg)
{
  struct bufferevent* bev = (struct bufferevent*)arg;  
  
  char sendBuf[BUFFER_MAX_SIZE];
  read(fd,sendBuf,BUFFER_MAX_SIZE);
  
  bufferevent_write(bev,sendBuf,strlen(sendBuf));
}

int main(int argc, char **argv)
{
  struct event_base *base;

  struct sockaddr_in svr_addr;
#ifdef WIN32
  WSADATA wsa_data;
  WSAStartup(0x0201, &wsa_data);
#endif

  base = event_base_new();
  if (!base) {
  	  fprintf(stderr, "Could not initialize libevent!\n");
  	  return 1;
  }

  evutil_socket_t sockfd = socket(AF_INET,SOCK_STREAM,0);
  struct bufferevent* bev = bufferevent_socket_new(base,sockfd,BEV_OPT_CLOSE_ON_FREE);

  memset(&svr_addr, 0, sizeof(svr_addr));
  svr_addr.sin_family = AF_INET;
  svr_addr.sin_port = htons(PORT);
  svr_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
/*
  int enable = 1;
  if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable)) < 0)
    printf("ERROR: TCP_NODELAY SETTING ERROR!\n");
*/
  
  struct event* ev_stdin = event_new(base,0 /*STDIN_FILENO*/,EV_READ|EV_PERSIST,stdin_cb,(void*)bev);
  event_add(ev_stdin,NULL);

  if( bufferevent_socket_connect(bev,(struct sockaddr*)&svr_addr,sizeof(svr_addr)) != 0 )
  {
    perror("bufferevent_socket_connect err");
    exit(1);
  }
  printf("connect svr success...\n");
  
  bufferevent_setcb(bev,read_cb,NULL,event_cb,(void*)ev_stdin); 
  bufferevent_enable(bev,EV_READ|EV_PERSIST);

  event_base_dispatch(base);
 
  bufferevent_free(bev);
  event_base_free(base);

  return 0;
}

客户端代码2

代码详解:
1.STDIN标准输入,使用bufferevent_sock_new监控
2.连接到服务器的套接字sock_fd,使用bufferevent_sock_new监控

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#ifndef WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif

#include <netinet/tcp.h>
#include <unistd.h>

#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>

static const int PORT = 8000;

#define BUFFER_MAX_SIZE 1024

static void read_cb(struct bufferevent *bev, void *arg)
{
  char recvbuf[BUFFER_MAX_SIZE] = {'\0'};
  struct evbuffer* input = bufferevent_get_input(bev);
  int n = evbuffer_get_length(input);
  
  bufferevent_read(bev,recvbuf,n);
  recvbuf[n]='\0';
  printf("recv = %s\n",recvbuf);
}

static void event_cb(struct bufferevent *bev, short events, void *arg)
{
  if (events & BEV_EVENT_EOF) 
  {
 	  printf("Connection closed.\n");
  } 
  else if (events & BEV_EVENT_ERROR) 
  {
    printf("Got an error on the connection: %s\n",strerror(errno));
	}
  else if (events & BEV_EVENT_CONNECTED)
  {
    printf("client has connect server successfully...\n");
    return;
  }

  struct event* ev_stdin = (struct event*)arg;
  event_free(ev_stdin);
  bufferevent_free(bev);
}
static void stdin_cb(struct bufferevent *stdin_bev, void *arg)
{
  struct bufferevent* bev = (struct bufferevent*)arg;  
  
  char sendBuf[BUFFER_MAX_SIZE] = {'\0'};
  bufferevent_read(stdin_bev,sendBuf,BUFFER_MAX_SIZE);
  bufferevent_write(bev,sendBuf,strlen(sendBuf));
}

int main(int argc, char **argv)
{
  struct event_base *base;
  struct sockaddr_in svr_addr;
#ifdef WIN32
  WSADATA wsa_data;
  WSAStartup(0x0201, &wsa_data);
#endif

  base = event_base_new();
  if (!base) {
	  fprintf(stderr, "Could not initialize libevent!\n");
	  return 1;
  }

  evutil_socket_t sockfd = socket(AF_INET,SOCK_STREAM,0);
  struct bufferevent* bev = bufferevent_socket_new(base,sockfd,BEV_OPT_CLOSE_ON_FREE);

  memset(&svr_addr, 0, sizeof(svr_addr));
  svr_addr.sin_family = AF_INET;
  svr_addr.sin_port = htons(PORT);
  svr_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
/*
  int enable = 1;
  if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable)) < 0)
    printf("ERROR: TCP_NODELAY SETTING ERROR!\n");
*/
  
  //struct event* ev_stdin = event_new(base,0 /*STDIN_FILENO*/,EV_READ|EV_PERSIST,stdin_cb,(void*)bev);
  //event_add(ev_stdin,NULL);
  
  struct bufferevent* bev_stdin = bufferevent_socket_new(base,0 /*STDIN_FILED*/,BEV_OPT_CLOSE_ON_FREE);
  bufferevent_setcb(bev_stdin,stdin_cb,NULL,NULL,(void*)bev);
  bufferevent_enable(bev_stdin,EV_READ|EV_PERSIST);

  if( bufferevent_socket_connect(bev,(struct sockaddr*)&svr_addr,sizeof(svr_addr)) != 0 )
  {
    perror("bufferevent_socket_connect err");
    exit(1);
  }
  printf("connect svr success...\n");
  
  bufferevent_setcb(bev,read_cb,NULL,event_cb,(void*)bev_stdin); 
  bufferevent_enable(bev,EV_READ|EV_PERSIST);

  event_base_dispatch(base);
  
  bufferevent_free(bev);
  event_base_free(base);

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值