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

首先是服务端:

#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> #include <stdio.h>
#include <string.h> #include <event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/thread.h> using namespace std; void listener_cb(evconnlistener *listener, evutil_socket_t fd,
sockaddr *sock, int socklen, void *arg); void socket_read_cb(bufferevent *bev, void *arg); void socket_event_cb(bufferevent *bev, short events, void *arg); int main(int argc, char **argv) { sockaddr_in sin;
memset(&sin, , sizeof(sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(); event_base *base = event_base_new();
evconnlistener *listener
= evconnlistener_new_bind(base,
listener_cb, base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
, (sockaddr*)&sin, sizeof(sockaddr_in)); event_base_dispatch(base); evconnlistener_free(listener);
event_base_free(base); } void listener_cb(evconnlistener *listener, evutil_socket_t fd,
sockaddr *sock, int socklen, void *arg) { printf("accept a client %d\n", fd);
event_base *base = (event_base *) arg; bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL);
bufferevent_enable(bev, EV_READ | EV_PERSIST); } void socket_read_cb(bufferevent *bev, void *arg) {
char msg[];
size_t len = bufferevent_read(bev, msg, sizeof(msg) - ); msg[len] = '\0';
printf("Server read the data: %s\n", msg); char reply[] = "I have read your data."; bufferevent_write(bev, reply, strlen(reply));
} void socket_event_cb(bufferevent *bev, short events, void *arg) {
if (events & BEV_EVENT_EOF) {
printf("connection closed\n");
}
else if (events & BEV_EVENT_ERROR) {
printf("some other error\n");
} bufferevent_free(bev);
}

编译命令:

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文件:

CXX=/opt/compiler/gcc-4.8.2/bin/g++

INCPATH= \
/home/work/.jumbo/include/ DEP_LDFLAGS= \
-L/home/work/.jumbo/lib/ DEP_LDLIBS= \
-levent \
-lpthread TARGET= lserver lclient all : $(TARGET) lserver : lserver.cc
$(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS) lclient : lclient.cc
$(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS) .PHONY : all clean clean :
rm -rf $(TARGET)

然后是客户端:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/util.h> int tcp_connect_server(const char *server_ip, int port); void cmd_msg_cb(int fd, short events, void *arg); void server_msg_cb(bufferevent *bev, void *arg); void event_cb(bufferevent *bev, short event, void *arg); int main(int argc, char **argv) {
if (argc < ) {
printf("please input IP and port\n");
return ;
} event_base *base = event_base_new(); bufferevent *bev = bufferevent_socket_new(base, -, BEV_OPT_CLOSE_ON_FREE); event *ev_cmd = event_new(base, STDIN_FILENO,
EV_READ|EV_PERSIST,
cmd_msg_cb, (void *)bev); event_add(ev_cmd, NULL); sockaddr_in server_addr;
memset(&server_addr, , sizeof(server_addr)); server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[]));
inet_aton(argv[], &server_addr.sin_addr); bufferevent_socket_connect(bev, (sockaddr *)&server_addr, sizeof(server_addr)); bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void *)ev_cmd);
bufferevent_enable(bev, EV_READ|EV_PERSIST); event_base_dispatch(base); printf("Finished\n");
return ; } void cmd_msg_cb(int fd, short events, void *arg) {
char msg[]; int ret = read(fd, msg, sizeof(msg));
if (ret < ) {
perror("read fail.\n");
exit();
} bufferevent *bev = (bufferevent *)arg;
bufferevent_write(bev, msg, ret);
} void server_msg_cb(bufferevent *bev, void *arg) {
char msg[]; size_t len = bufferevent_read(bev, msg, sizeof(msg)-);
msg[len] = '\0'; printf("Recv %s from server.\n", msg);
} void event_cb(bufferevent *bev, short event, void *arg) {
if (event & BEV_EVENT_EOF) {
printf("Connection closed.\n");
}
else if (event & BEV_EVENT_ERROR) {
printf("Some other error.\n");
}
else if (event & BEV_EVENT_CONNECTED) {
printf("Client has successfully cliented.\n");
return;
} bufferevent_free(bev); // free event_cmd
// need struct as event is defined as parameter
struct event *ev = (struct event *)arg;
event_free(ev);
}

编译命令:

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

运行服务器命令:

./lserver

运行客户端命令:

./lclient 127.0.0.1 

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

[server]$ ./lserver
accept a client
Server read the data: aaa Server read the data: bbb Server read the data: ccc Server read the data: ddd Server read the data: eeeee
[client]$ ./lclient 127.0.0.1
Client has successfully cliented.
aaa
Recv I have read your data. from server.
bbb
Recv I have read your data. from server.
ccc
Recv I have read your data. from server.
ddd
Recv I have read your data. from server.
eeeee
Recv I have read your data. from server.

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

[server]$ ./lserver
accept a client
Server read the data: aaa Server read the data: bbb Server read the data: ccc Server read the data: ddd Server read the data: eeeee connection closed
accept a client
Server read the data: ttt

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

[client]$ ./lclient 127.0.0.1
Client has successfully cliented.
ttt
Recv I have read your data. from server.
Connection closed.
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. 使用compile_scripts.php脚本,生成lua打包的zip,解决加密问题

    @echo off set DIR=%~dp0 set TEMPLATE_ROOT=%DIR%.. echo %TEMPLATE_ROOT%\quick\bin\win32\php.exe echo ...

  2. class打包成exe方式

    首先运行dos命令 jar -cvf **.jar *.class 把所有文件打包成jar包 用解压器打开jar包 打开meta-inf文件夹 打开用记事本打开main.mf文件 增加语句Main-C ...

  3. Exact Change(背包HDU2753)

    Exact Change Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...

  4. request、response 中文乱码问题与解决方式

    request乱码指的是:浏览器向服务器发送的请求参数中包含中文字符,服务器获取到的请求参数的值是乱码:   response乱码指的是:服务器向浏览器发送的数据包含中文字符,浏览器中显示的是乱码: ...

  5. 列出本机JCE提供者,支持消息摘要算法,支持公钥私钥算法

    import java.security.Provider; import java.security.Security; public class TestBouncyCastle { public ...

  6. 洛谷 P1896 [SCOI2005]互不侵犯King

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入输出格式 输入格式: 只有一行,包 ...

  7. uTenux\AT91SAM3S4C开发套件———硬件电路介绍

    无论写什么嵌入式软件,我们都应该首先对硬件有所了解,这样更有助于我们写出高效精简的程序代码.本次活动我们使用的硬件平台是有悠龙公司提供的uTenux\AT91SAM3S4C开发套件,在悠龙公司的主页可 ...

  8. 动态加载JS

    <script> Date.prototype.format = function(format) { var o = { , //month "d+" : this. ...

  9. 【转载】在Linux中使用VS Code编译调试C++项目

    原文:在Linux中使用VS Code编译调试C++项目 最近项目需求,需要在Linux下开发C++相关项目,经过一番摸索,简单总结了一下如何通过VS Code进行编译调试的一些注意事项. 关于VS ...

  10. JaveScript变量作用域说明

    JaveScript变量作用域说明     一:将var类型的变量视为变量,不带var类型的变量视为常量(但是注意php的常量不可以重新定义,而javascript中不带var类型的变量可以重新定义) ...