libevent编写echo服务器

逃离我推掉我的手 2022-06-17 02:18 268阅读 0赞

为了使用libevent,编写一个echo回射服务器程序。

1. 准备工作

在深入浅出Libevent一书上提到,如果是源码学习的话使用libevent1.4版本,如果是使用的话一般用libevent2.x版本。
因此,在libevent.org上将libevent2.0.20-stable版本的源码下载下来,编译,安装:

  1. ./configure --prefix=INSTALL_DIR
  2. make
  3. make install

2. 编写Makefile

在Makefile中,需要指定libevent安装的头文件目录(gcc中-I选项)和库文件目录(gcc中-L选项),以及加上编译标志-levent

  1. PROGS=echo
  2. CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \
  3. *.lc *.lh *.bsdi *.sparc *.uw
  4. LIBEVENT_DIRECTORY = /home/zhangxiao/libevent/src/src2 ### INSTALL DIR
  5. LIBEVENT_INCLUDE = $(LIBEVENT_DIRECTORY)/include
  6. LIBEVENT_LIBRARY = $(LIBEVENT_DIRECTORY)/lib
  7. SRC=${shell pwd}/src
  8. OUTPUT:=${shell pwd}/bin
  9. MAKE_BIN_DIR := ${shell mkdir -p $(OUTPUT) }
  10. all : ${PROGS}
  11. CFLAGS+=-g -I${LIBEVENT_INCLUDE}
  12. LDFLAGS+=-L${LIBEVENT_LIBRARY} -levent -lpthread -lrt
  13. echo:${SRC}/echo.o
  14. @${CC} ${CFLAGS} -o ${OUTPUT}/$@ $^ ${LDFLAGS}
  15. clean:
  16. @rm -rf ${OUTPUT} \
  17. @rm -rf ${SRC}/*.o
  18. .PHONY: all clean

3. 编写echo server

由于libevent的Reactor设计模式,我们需要为网络事件编写回调函数(Handler),例如onAccept,onRead等等

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <assert.h>
  5. #include <event2/event.h>
  6. #include <event2/bufferevent.h>
  7. #define LISTEN_PORT 9999
  8. #define LISTEN_BACKLOG 32
  9. void do_accept(evutil_socket_t listener, short event,void *arg);
  10. void read_cb(struct bufferevent *bev,void *arg);
  11. void error_cb(struct bufferevent*bev,short event,void *arg);
  12. void write_cb(struct bufferevent*bev,void *arg);
  13. int main(int argc,char **argv)
  14. {
  15. int ret;
  16. evutil_socket_t listener;
  17. listener=socket(AF_INET,SOCK_STREAM,0);
  18. assert(listener>0);
  19. evutil_make_listen_socket_reuseable(listener);
  20. struct sockaddr_in sin;
  21. sin.sin_family=AF_INET;
  22. sin.sin_addr.s_addr=0;
  23. sin.sin_port=htons(LISTEN_PORT);
  24. if (bind(listener, (struct sockaddr *)&sin, sizeof(sin)) < 0)
  25. {
  26. perror("bind");
  27. return 1;
  28. }
  29. if (listen(listener, LISTEN_BACKLOG) < 0)
  30. {
  31. perror("listen");
  32. return 1;
  33. }
  34. printf ("Listening...\r\n");
  35. evutil_make_socket_nonblocking(listener);
  36. struct event_base *base = event_base_new();
  37. assert(base != NULL);
  38. struct event *listen_event;
  39. listen_event = event_new(base, //base
  40. listener, //fd
  41. EV_READ|EV_PERSIST,//event
  42. do_accept, //call back
  43. (void*)base);//args
  44. event_add(listen_event,NULL);
  45. event_base_dispatch(base);
  46. printf("The End.\r\n");
  47. return 0;
  48. }
  49. void do_accept(evutil_socket_t listener, short event, void *arg)
  50. {
  51. struct event_base *base = (struct event_base *)arg;
  52. evutil_socket_t fd;
  53. struct sockaddr_in sin;
  54. socklen_t slen = sizeof(sin);
  55. fd = accept(listener, (struct sockaddr *)&sin, &slen);
  56. if (fd < 0) {
  57. perror("accept");
  58. return;
  59. }
  60. if (fd > FD_SETSIZE) { //这个if是参考了那个ROT13的例子,貌似是官方的疏漏,从select-based例子里抄过来忘了改
  61. perror("fd > FD_SETSIZE\n");
  62. return;
  63. }
  64. printf("ACCEPT: fd = %u\n", fd);
  65. struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  66. bufferevent_setcb(bev, read_cb, NULL, error_cb, arg);
  67. bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
  68. }
  69. void read_cb(struct bufferevent *bev, void *arg)
  70. {
  71. #define MAX_LINE 256
  72. char line[MAX_LINE+1];
  73. int n;
  74. evutil_socket_t fd = bufferevent_getfd(bev);
  75. while (n = bufferevent_read(bev, line, MAX_LINE), n > 0) {
  76. line[n] = '\0';
  77. printf("fd=%u, read line: %s\n", fd, line);
  78. bufferevent_write(bev, line, n);
  79. }
  80. }
  81. void write_cb(struct bufferevent *bev, void *arg) {}
  82. void error_cb(struct bufferevent *bev, short event, void *arg)
  83. {
  84. evutil_socket_t fd = bufferevent_getfd(bev);
  85. printf("fd = %u, ", fd);
  86. if (event & BEV_EVENT_TIMEOUT) {
  87. printf("Timed out\n"); //if bufferevent_set_timeouts() called
  88. }
  89. else if (event & BEV_EVENT_EOF) {
  90. printf("connection closed\n");
  91. }
  92. else if (event & BEV_EVENT_ERROR) {
  93. printf("some other error\n");
  94. }
  95. bufferevent_free(bev);
  96. }

4. 测试

使用nc测试即可

5. 参考

深入浅出 Libevent
Programming with libevent

发表评论

表情:
评论列表 (有 0 条评论,268人围观)

还没有评论,来说两句吧...

相关阅读