参考了网上的一些例子,实验了基于bufferevent的开发。

首先是服务端:

  1. #include <netinet/in.h>
  2. #include <sys/socket.h>
  3. #include <unistd.h>
  4.  
  5. #include <stdio.h>
  6. #include <string.h>
  7.  
  8. #include <event.h>
  9. #include <event2/listener.h>
  10. #include <event2/bufferevent.h>
  11. #include <event2/thread.h>
  12.  
  13. using namespace std;
  14.  
  15. void listener_cb(evconnlistener *listener, evutil_socket_t fd,
  16. sockaddr *sock, int socklen, void *arg);
  17.  
  18. void socket_read_cb(bufferevent *bev, void *arg);
  19.  
  20. void socket_event_cb(bufferevent *bev, short events, void *arg);
  21.  
  22. int main(int argc, char **argv) {
  23.  
  24. sockaddr_in sin;
  25. memset(&sin, , sizeof(sockaddr_in));
  26. sin.sin_family = AF_INET;
  27. sin.sin_port = htons();
  28.  
  29. event_base *base = event_base_new();
  30. evconnlistener *listener
  31. = evconnlistener_new_bind(base,
  32. listener_cb, base,
  33. LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
  34. , (sockaddr*)&sin, sizeof(sockaddr_in));
  35.  
  36. event_base_dispatch(base);
  37.  
  38. evconnlistener_free(listener);
  39. event_base_free(base);
  40.  
  41. }
  42.  
  43. void listener_cb(evconnlistener *listener, evutil_socket_t fd,
  44. sockaddr *sock, int socklen, void *arg) {
  45.  
  46. printf("accept a client %d\n", fd);
  47. event_base *base = (event_base *) arg;
  48.  
  49. bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  50.  
  51. bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL);
  52. bufferevent_enable(bev, EV_READ | EV_PERSIST);
  53.  
  54. }
  55.  
  56. void socket_read_cb(bufferevent *bev, void *arg) {
  57. char msg[];
  58. size_t len = bufferevent_read(bev, msg, sizeof(msg) - );
  59.  
  60. msg[len] = '\0';
  61. printf("Server read the data: %s\n", msg);
  62.  
  63. char reply[] = "I have read your data.";
  64.  
  65. bufferevent_write(bev, reply, strlen(reply));
  66. }
  67.  
  68. void socket_event_cb(bufferevent *bev, short events, void *arg) {
  69. if (events & BEV_EVENT_EOF) {
  70. printf("connection closed\n");
  71. }
  72. else if (events & BEV_EVENT_ERROR) {
  73. printf("some other error\n");
  74. }
  75.  
  76. bufferevent_free(bev);
  77. }

编译命令:

  1. g++ -o lserver lserver.cpp -I/usr/local/include -levent -L/usr/local/lib -Wl,-rpath=/usr/local/lib

2016.09.28

我把server和client编译的命令,整理成了新的Makefile文件:

  1. CXX=/opt/compiler/gcc-4.8.2/bin/g++
  2.  
  3. INCPATH= \
  4. /home/work/.jumbo/include/
  5.  
  6. DEP_LDFLAGS= \
  7. -L/home/work/.jumbo/lib/
  8.  
  9. DEP_LDLIBS= \
  10. -levent \
  11. -lpthread
  12.  
  13. TARGET= lserver lclient
  14.  
  15. all : $(TARGET)
  16.  
  17. lserver : lserver.cc
  18. $(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS)
  19.  
  20. lclient : lclient.cc
  21. $(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS)
  22.  
  23. .PHONY : all clean
  24.  
  25. clean :
  26. rm -rf $(TARGET)

然后是客户端:

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <arpa/inet.h>
  5. #include <errno.h>
  6. #include <unistd.h>
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11.  
  12. #include <event.h>
  13. #include <event2/bufferevent.h>
  14. #include <event2/buffer.h>
  15. #include <event2/util.h>
  16.  
  17. int tcp_connect_server(const char *server_ip, int port);
  18.  
  19. void cmd_msg_cb(int fd, short events, void *arg);
  20.  
  21. void server_msg_cb(bufferevent *bev, void *arg);
  22.  
  23. void event_cb(bufferevent *bev, short event, void *arg);
  24.  
  25. int main(int argc, char **argv) {
  26. if (argc < ) {
  27. printf("please input IP and port\n");
  28. return ;
  29. }
  30.  
  31. event_base *base = event_base_new();
  32.  
  33. bufferevent *bev = bufferevent_socket_new(base, -, BEV_OPT_CLOSE_ON_FREE);
  34.  
  35. event *ev_cmd = event_new(base, STDIN_FILENO,
  36. EV_READ|EV_PERSIST,
  37. cmd_msg_cb, (void *)bev);
  38.  
  39. event_add(ev_cmd, NULL);
  40.  
  41. sockaddr_in server_addr;
  42. memset(&server_addr, , sizeof(server_addr));
  43.  
  44. server_addr.sin_family = AF_INET;
  45. server_addr.sin_port = htons(atoi(argv[]));
  46. inet_aton(argv[], &server_addr.sin_addr);
  47.  
  48. bufferevent_socket_connect(bev, (sockaddr *)&server_addr, sizeof(server_addr));
  49.  
  50. bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void *)ev_cmd);
  51. bufferevent_enable(bev, EV_READ|EV_PERSIST);
  52.  
  53. event_base_dispatch(base);
  54.  
  55. printf("Finished\n");
  56. return ;
  57.  
  58. }
  59.  
  60. void cmd_msg_cb(int fd, short events, void *arg) {
  61. char msg[];
  62.  
  63. int ret = read(fd, msg, sizeof(msg));
  64. if (ret < ) {
  65. perror("read fail.\n");
  66. exit();
  67. }
  68.  
  69. bufferevent *bev = (bufferevent *)arg;
  70. bufferevent_write(bev, msg, ret);
  71. }
  72.  
  73. void server_msg_cb(bufferevent *bev, void *arg) {
  74. char msg[];
  75.  
  76. size_t len = bufferevent_read(bev, msg, sizeof(msg)-);
  77. msg[len] = '\0';
  78.  
  79. printf("Recv %s from server.\n", msg);
  80. }
  81.  
  82. void event_cb(bufferevent *bev, short event, void *arg) {
  83. if (event & BEV_EVENT_EOF) {
  84. printf("Connection closed.\n");
  85. }
  86. else if (event & BEV_EVENT_ERROR) {
  87. printf("Some other error.\n");
  88. }
  89. else if (event & BEV_EVENT_CONNECTED) {
  90. printf("Client has successfully cliented.\n");
  91. return;
  92. }
  93.  
  94. bufferevent_free(bev);
  95.  
  96. // free event_cmd
  97. // need struct as event is defined as parameter
  98. struct event *ev = (struct event *)arg;
  99. event_free(ev);
  100. }

编译命令:

  1. g++ -o lclient lclient.cpp -I/usr/local/include -levent -L/usr/local/lib -Wl,-rpath=/usr/local/lib

运行服务器命令:

  1. ./lserver

运行客户端命令:

  1. ./lclient 127.0.0.1

多次交互之后的两边输出结果为:

  1. [server]$ ./lserver
  2. accept a client
  3. Server read the data: aaa
  4.  
  5. Server read the data: bbb
  6.  
  7. Server read the data: ccc
  8.  
  9. Server read the data: ddd
  10.  
  11. Server read the data: eeeee
  1. [client]$ ./lclient 127.0.0.1
  2. Client has successfully cliented.
  3. aaa
  4. Recv I have read your data. from server.
  5. bbb
  6. Recv I have read your data. from server.
  7. ccc
  8. Recv I have read your data. from server.
  9. ddd
  10. Recv I have read your data. from server.
  11. eeeee
  12. Recv I have read your data. from server.

如果先关闭客户端(Ctrl-C,也就是SIGINT),服务器端会打印一条提示,但是仍然可以接受其他的请求。

  1. [server]$ ./lserver
  2. accept a client
  3. Server read the data: aaa
  4.  
  5. Server read the data: bbb
  6.  
  7. Server read the data: ccc
  8.  
  9. Server read the data: ddd
  10.  
  11. Server read the data: eeeee
  12.  
  13. connection closed
  14. accept a client
  15. Server read the data: ttt

如果先关闭服务器端(Ctrl-C,也就是SIGINT),客户端也会关闭:

  1. [client]$ ./lclient 127.0.0.1
  2. Client has successfully cliented.
  3. ttt
  4. Recv I have read your data. from server.
  5. Connection closed.
  6. Finished

这是因为在客户端上关联的event,包括socket的event(通过bufferevent_free关闭),和cmd的event(通过event_free关闭),都已经被关闭了。那么整个event_base_dispatch的循环就返回了。

使用bufferevent进行libevent服务端和客户端的开发的更多相关文章

  1. C# 编写WCF简单的服务端与客户端

    http://www.wxzzz.com/1860.html Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Win ...

  2. linux(centos 6.4)下安装php memcache服务端及其客户端(详细教程)

    前言 在搭建个人博客时,由于没有使用任何框架,纯手工code前台和后台,导致遇到许多问题,其中一个问题就是mysql连接导致的页面相应速度异常低.在查询各种途径后,只能考虑使用memcache缓存.在 ...

  3. QTcpSocket-Qt使用Tcp通讯实现服务端和客户端

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QTcpSocket-Qt使用Tcp通讯实现服务端和客户端     本文地址:https:// ...

  4. asp.net获取服务端和客户端信息

    asp.net获取服务端和客户端信息 获取服务器名:Page.Server.ManchineName获取用户信息:Page.User 获取客户端电脑名:Page.Request.UserHostNam ...

  5. python thrift 服务端与客户端使用

    一.简介 thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, ...

  6. IE8下服务端获取客户端文件的路径为C:/fakePath问题的解决方案

    上一篇文章上提到,IE8下服务端获取客户端文件的路径时,会变成C:/fakePath问题,于是乎通过文件路径去获得文件大小就失败了. 上网搜了一下,主要原因是IE8因为安全考虑,在上传文件时屏蔽了真实 ...

  7. 如何排查APP服务端和客户端是否支持ATS

    服务端排查 取得客户端直接连接的服务端域名及端口,例如mob.com.cn,端口443,即HTTPS默认端口.针对公网可访问的生产环境地址,建议使用的在线监测工具.https://wosign.ssl ...

  8. (转)SVN 服务端、客户端安装及配置、导入导出项目

    SVN服务器搭建和使用(一) Subversion是优秀的版本控制工具,其具体的的优点和详细介绍,这里就不再多说. 首先来下载和搭建SVN服务器. 现在Subversion已经迁移到apache网站上 ...

  9. [C语言]一个很实用的服务端和客户端进行TCP通信的实例

    本文给出一个很实用的服务端和客户端进行TCP通信的小例子.具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考. (1)客户端程序,编写一个文件clie ...

随机推荐

  1. java面试每日一题5

    题目:企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%:利润高于10万元,低于20万元时,低于10万元的部分按10%提 成,高于10万元的部分,可可提成7.5%:20万到40 ...

  2. AR专用汉明码

    增强现实技术(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上相应图像.视频.3D模型的技术,这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动. ...

  3. c#danliemosih

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 打印机 ...

  4. phpcms常用函数

    1../libs/functions/global.func.php    --------------------------------------------------字符串安全处理函数--- ...

  5. Improving the GPA 分类: 贪心 HDU 比赛 2015-08-08 16:12 11人阅读 评论(0) 收藏

    Improving the GPA Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) ...

  6. 【20160924】GOCVHelper 图像增强部分(4)

    //使得rect区域半透明     Mat translucence(Mat src,Rect rect,int idepth){         Mat dst = src.clone();     ...

  7. 软件测试工作中涉及的Linux命令整理

    Linux文件系统命令 1. 安装火狐浏览器,首先得知道Linux系统是64位的还是32位的 uname -a 2. 将下载的火狐浏览器压缩包移动到指定目录(/user/local)下 sudo mv ...

  8. Java提高篇---TreeMap

    TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap的实现,但是为了与Java提高篇系列博文保持一致 ...

  9. 2016年11月3日 星期四 --出埃及记 Exodus 19:19

    2016年11月3日 星期四 --出埃及记 Exodus 19:19 and the sound of the trumpet grew louder and louder. Then Moses s ...

  10. P1533 可怜的狗狗

    http://www.luogu.org/problem/show?pid=1533 题目背景 小卡由于公务需要出差,将新家中的狗狗们托付给朋友嘉嘉,但是嘉嘉是一个很懒的人,他才没那么多时间帮小卡喂狗 ...