使用bufferevent进行libevent服务端和客户端的开发

参考了网上的一些例子,实验了基于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, 0, sizeof(sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8899);

    event_base *base = event_base_new();
    evconnlistener *listener
        = evconnlistener_new_bind(base,
                      listener_cb, base,
                      LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
                      10, (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[4096];
    size_t len = bufferevent_read(bev, msg, sizeof(msg) - 1);

    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

然后是客户端:

#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 < 3) {
        printf("please input IP and port\n");
        return 1;
    }

    event_base *base = event_base_new();

    bufferevent *bev = bufferevent_socket_new(base, -1, 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, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    inet_aton(argv[1], &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 0;

}

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.\n");
        exit(1);
    }

    bufferevent *bev = (bufferevent *)arg;
    bufferevent_write(bev, msg, ret);
}

void server_msg_cb(bufferevent *bev, void *arg) {
    char msg[1024];

    size_t len = bufferevent_read(bev, msg, sizeof(msg)-1);
    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 8899

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

[server]$ ./lserver
accept a client 7
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 8899
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 7
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 7
Server read the data: ttt

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

[client]$ ./lclient 127.0.0.1 8899
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的循环就返回了。

时间: 2024-10-22 22:10:28

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

webService服务端和客户端开发 简单实例

这几天一直在看webService相关的知识. webService是一个跨平台访问的第三方插件,方便易用,多平台使用. 开发中我们可能自己是服务端,提供webService接口给别人访问我们的系统:也有可能我们调用别人的webService接口去访问别人的系统(比如查询天气预报). 下面是服务端和客户端的开发,实际开发中我们只是其中一方. 服务端开发: ①创建一个服务类,运行main方法发布即可,服务端就开发完成了. package com.lijianbo.service; import j

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

http://www.wxzzz.com/1860.html Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台.整合了原有的windows通讯的 .net Remoting,WebService,Socket的机制,并融合有HTTP和FTP的相关技术.是Windows平台上开发分布式应用最佳的实践方式. 今天带如何一步一步实现WCF服务端与客户端的开发及基础讲解. 一.在Visual

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

前言 在搭建个人博客时,由于没有使用任何框架,纯手工code前台和后台,导致遇到许多问题,其中一个问题就是mysql连接导致的页面相应速度异常低.在查询各种途径后,只能考虑使用memcache缓存.在参考了许多文章后,终于成功的在centos6.4下安装memcache.由于发现在安装过程中,许多文章在有些细节没有解释清楚,导致我一直卡在一个问题上面.为了帮助其他可能和我遇到了同样问题的娃们,我准备也把我的安装过程详细介绍下,而不是ctrl+c,ctrl+v.希望对大家有帮助.(部分参考www.

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

版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QTcpSocket-Qt使用Tcp通讯实现服务端和客户端     本文地址:http://techieliang.com/2017/12/530/ 文章目录 1. 基本功能  1.1. pro文件配置  1.2. QTcpServer服务端建立  1.3. 客户端建立  1.4. 消息收发 2. 其他  2.1. 实现单服务器多客户端通讯  2.2. 关于QTcpServer  2.3.

关于ntp(时间同步协议)服务端和客户端的配置说明

本文主要写了一些在Linux(CentOS)服务器上配置ntp的经验,事件缘由来源于配置Zabbix监控ntp服务时的测试配置. NTP时间同步协议的服务端(ntpd服务)和客户端(ntpdate服)不能同时运行,即在运行ntpd服务后不能运行ntpdate服务,否则ntpdate服务会提示启动失败,而且日志中也会提示"the NTP socket is in use, exiting",如下图所示. 但客户端运行时,服务端可以运行,但服务端运行时,客户端不能运行,要运行客户端服务,就

socket服务端和客户端

#!/usr/bin/env python#encoding: utf-8import socketdef handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK\r\n\r\n") client.send("Hello, World") def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREA

用Java实现HTTP Multipart的服务端和客户端

今天简单介绍一下如何用Java支持HTTP Multipart的request和response. 整个项目的代码可以在https://github.com/mcai4gl2/multi下载. 在这个程序里,我们的业务场景很简单.在服务端有一个随机数生成器,可以生成随机的Integer和Guid,客户端通过服务,可以请求一个或多个随机数.同时,客户端可以向服务端发送一个或多个随机数,这些随机数会被加入到一个队列中,被其他的客户端通过请求获得.以下是我们的随机数Bean的定义: [java] vi

C# Socket服务端和客户端互相send和receive

服务端 1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Net.Sockets; 5 using System.Net; 6 using System.Threading; 7  8 namespace Controller 9 {10     public static class SocketServer11     {12         private stat

CnetOS 6.6 rsync 的服务端和客户端配置

CentOS 6.6 rsync 的服务端和客户端配置 基本信息 系统版本 主机名 IP地址 角色 CentOS  6.6 backup 10.0.0.10 rsync服务端 CentOS  6.6 lamp01 10.0.0.8 rsync客户端 CentOS  6.6 lnmp02 10.0.0.9 rsync客户端 服务端配置 创建rsync配置文件,并写入配置内容(默认rsync文件是不存在的,需要创建) [[email protected] ~]# touch/etc/rsyncd.c