libevent(2)

client.cpp


// App02.cpp : 定义控制台应用程序的入口点。
//
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <iostream>
#include <thread>
#include <atomic>

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

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

std::atomic_bool write_over;

void eventcb(struct bufferevent *bev, short events, void *ptr)
{
if (events & BEV_EVENT_CONNECTED)
{
/* We‘re connected to 127.0.0.1:8080. Ordinarily we‘d do
something here, like start reading or writing. */
}
else if (events & BEV_EVENT_ERROR)
{
/* An error occured while connecting. */
}
}

//接收Server来的消息
static void conn_readcb(struct bufferevent *bev, void *user_data)//arg1:发生了事件的bufferevent,最后一个是用户提供的参数,可以通过这个向回调传递参数
{
char buf[50] = {0};
int len = bufferevent_read(bev, buf, sizeof(buf));
std::cout<<"来自Server:"<< buf << std::endl;
}

static void conn_writecb(struct bufferevent *bev, void *user_data)
{
write_over = true;
//int ret = bufferevent_write(bev, "我是一个客户端!", 20);
}

struct event_base *g_base;//管理事件

int main()
{
write_over = false;
struct bufferevent *bev;
struct sockaddr_in sin;
#ifdef WIN32
WSADATA wsa_data;
WSAStartup(0x0201, &wsa_data);
#endif
//event支持多线程的初始化函数
if(-1 == evthread_use_windows_threads())
return false;

g_base = event_base_new();

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
sin.sin_port = htons(9527); /* Port 9527 */

bev = bufferevent_socket_new(g_base, -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);//创建基于套接字的bufferevent

// bufferevent_setcb(bev, NULL, NULL, eventcb, NULL);

if (bufferevent_socket_connect(bev,//connect套接字
(struct sockaddr *)&sin, sizeof(sin)) < 0)
{
/* Error starting connection */
std::cout<<"连接失败!\n";
bufferevent_free(bev);
return -1;
}
bufferevent_setcb(bev, conn_readcb, /*conn_writecb*/nullptr, eventcb, "回调参数");//修改回调
bufferevent_enable(bev, EV_READ | EV_WRITE );

std::thread th([]
{
event_base_dispatch(g_base);//循环处理事件
});

int ret = bufferevent_write(bev, "我是客户端-1", 20);

std::cout<<"输入你想发送的内容:\n";
int count = 0;
while(1)
{
// if(write_over)
{
write_over = false;
char msg[50] = {0};
sprintf(msg, "第%d次发送信息!", ++count);
bufferevent_write(bev, msg, strlen(msg) + 1);
Sleep(500);
}
// Sleep(50);
}

th.join();
std::cout<<" over!\n";
getchar();
return 0;
}

server.cpp


// App01.cpp : 定义控制台应用程序的入口点。
//
#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/thread.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/bufferevent_struct.h>
#include <thread>
#include <iostream>
#include <vector>

/* 设置计数,只允许echo_write_cb调用一次 */
static int count = 1;
static std::vector<struct bufferevent *> g_bev;//bufferevent缓冲区

/*当有数据可读的时候,会调用这个函数 */
//读取回调函数
static void echo_read_cb(struct bufferevent *bev, void *ctx)
{
printf("读:echo_read_cb is called\n");
char bufs[1000] = {0};
bufferevent_read(bev, bufs, sizeof(bufs));
std::cout<< bufs <<"\n";
return;

printf("读:echo_read_cb is called\n");
struct evbuffer *input = bufferevent_get_input(bev);
struct evbuffer *output = bufferevent_get_output(bev);

size_t len = evbuffer_get_length(input);
printf("evbuffer input length is: %lu\n", (unsigned long)len);

//evbuffer_add_buffer(output, input);

char buf[1024];
int n;
n = evbuffer_remove(input, buf, sizeof(buf));
printf("copy bytes == %d\n", n);
printf("copy buf: %s\n", buf);
}

//写入回调函数
static void echo_write_cb(struct bufferevent *bev, void *ctx)
{

printf("写:echo_write_cb is called\n");
char sendbuffer[] = "yes, i recv your message!\n";
return;

struct evbuffer *output = bufferevent_get_output(bev);

if(count == 1)
{
int result = evbuffer_add(output, sendbuffer, strlen(sendbuffer));
printf("evbuffer_add result = %d\n", result);
}

count++;
int len = evbuffer_get_length(output);
evbuffer_drain(output, len);
}

/*当客户端结束的时候,肯定会调用这个函数 */
//事件回调函数
static void echo_event_cb(struct bufferevent *bev, short events, void *ctx)
{
printf("状态:echo_event_cb is called\n");
if(events & BEV_EVENT_ERROR)
perror("Error from bufferevent");
if(events & BEV_EVENT_EOF | BEV_EVENT_ERROR)
{
bufferevent_free(bev);
printf("bufferevent_free is called\n");
}
printf("-------------------------------\n\n");

}

//client连接回调
static void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr*address, int socklen, void *ctx)
{
printf("连接:Accept_conn_cb is called\n");
struct event_base *base = evconnlistener_get_base(listener);//返回监听器关联的event_base
struct bufferevent *bev = bufferevent_socket_new(base, fd,//创建基于套接字的bufferevent
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
if (!bev)
{
fprintf(stderr, "Error constructing bufferevent!");
event_base_loopbreak(base);
return ;
}
g_bev.push_back(bev);

bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, "Server参数");//设置读回调,错误事件回调,null表示禁止回调,cbarg向回调传递参数

bufferevent_enable(bev, EV_READ|EV_WRITE); //开启缓冲区上的读,写事件
}

//连接监听器错误回调函数
static void accept_error_cb(struct evconnlistener *listener, void *ctx)
{
printf("监听错误:Accept_error_cb is called\n");
struct event_base *base = evconnlistener_get_base(listener);
int err = EVUTIL_SOCKET_ERROR();
fprintf(stderr, "Got an error");

event_base_loopexit(base, NULL);

}

struct event_base *g_base;

int main(int argc, char **argv)
{
struct evconnlistener *listener;
struct sockaddr_in sin;

int port = 9527;

if(argc > 1)
{
port = atoi(argv[1]);
}
if(port <= 0 || port > 65535)
{
puts("Invalid port");
return 1;
}
#ifdef WIN32
WSADATA wsa_data;
WSAStartup(0x0201, &wsa_data);//启动异步socket
#endif
if(-1 == evthread_use_windows_threads())//event多线程支持
return false;

g_base = event_base_new();//创建一个event_base
if(!g_base)
{
puts("could‘t open event_base");
return 1;
}

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0);
sin.sin_port = htons(port);
//分配返回一个监听器对象,有连接会回调accept_conn_cb函数,绑定iP,port
listener = evconnlistener_new_bind(g_base, accept_conn_cb, NULL,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
(struct sockaddr*)&sin, sizeof(sin));
if(!listener)
{
perror("could‘t not create listener");
return 1;
}

evconnlistener_set_error_cb(listener, accept_error_cb);//侦听错误
std::thread th([]
{
event_base_dispatch(g_base);//程序进入无线循环,等待就绪事件并执行事件处理
});
int count = 0;
for(;;)
{
if(!g_bev.empty())
{
for(auto it : g_bev)
{
char msg[50] = {0};
sprintf(msg, "欢迎!Server send!%d", count);
bufferevent_write(it, msg, 50);//想缓冲区添加数据
}
count++;
}
Sleep(50);
}
th.join();
return 0;
}

libevent(2)

时间: 2024-10-21 09:48:24

libevent(2)的相关文章

Windows 上静态编译 Libevent 2.0.10 并实现一个简单 HTTP 服务器(无数截图)

[文章作者:张宴 本文版本:v1.0 最后修改:2011.03.30 转载请注明原文链接:http://blog.s135.com/libevent_windows/] 本文介绍了如何在 Windows 操作系统中,利用微软 Visual Studio 2005 编译生成 Libevent 2.0.10 静态链接库,并利用 Libevent 静态链接库,实现一个简单的 HTTP Web服务器程序:httpd.exe. 假设 Visual Studio 2005 的安装路径为“D:\Program

1 Linux 安装 Libevent

Libevent官网:http://libevent.org/ 在线文档:http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/ 下载地址:https://github.com/libevent/libevent/releases/ 解压,编译,安装 创建文件夹 [email protected]:~$ mkdir libevent [email protected]:~$ cd libevent/ 解压文件: [email protec

浅谈libevent的使用--事件和数据缓冲

首先在学习libevent库的使用前,我们还要从基本的了解开始,已经熟悉了epoll以及reactor,然后从event_base学习,依次学习事件event.数据缓冲Bufferevent和数据封装evBuffer等,再结合具体的几个实例来了解libevent库的一些基本使用,有助于我们理解它的一些内部实现(由于之前我已经写过一篇epoll反应堆模型的,所以这里就不再介绍,直接从event_base开始介绍). libevent下载与安装: 在官网上找到 libevent-2.0.22-sta

libevent for qt网络模块

libevent for qt网络模块,直接替换qt的select模型,支持epoll,select,pool.使用非常简单,无需修改以前的代码结构 最近在开发im服务器,需要大并发链接.QT默认的是使用select模型的,这种轮询方式非常慢.在高并发连接,我们需要epoll才能发挥linux服务器的性能.而且使用简单,整个服务端代码架构无需修改,设置QT的分发事件就可以使用了,只要在main里面添加 : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 int main(int

libevent学习一

首先,libevent是个什么东西呢?通过阅读:官网. libevent:一个事件通知库.libevent的API提供了一个可以执行回调函数的机制.这些事件可以是一个文件描述符或到达指定时间.而且,libevent也支持由signals或常规的timeout产生的回调. libevent是用来替代网络服务器上的时间循环的.一个程序只需要去调用event_dispatch()然后去动态的增加或删除事件,而不用去改变事件循环. 目前,libevent支持/dev/poll, kqueue(2), e

libevent在windows下使用步骤详解

libevent是一个常用的网络库,下面就看看在windows下面编译测试的过程吧. 一 环境 系统:win8.1 编译器:VS2013 官方下载地址:http://libevent.org/ 版本:2.0.22-stable 二 编译静态库 1 解压 把上面下载到libevent-2.0.22-stable.tar.gz解压,得到libevent-2.0.22-stable文件夹 2 添加宏定义 在libevent-2.0.22-stable文件夹下找到下面三个文件: event_iocp.c

linux 基础学习编译安装php+mysql+python3+memcached+radis+rabbitmq+libevent+tcl+gcc+erlang

CentOS 6.9 编译安装 Nginx+PHP+MYSQL 0x01 环境约束 源码位置 /home/[用户文件夹] 源码编译安装位置  /usr/local/[软件名] CentOS6.9 x86 - 64 最小化安装 配置好网络 用户 使用Xshell登录 0x02 软件下载 内网地址: http://192.168.20.252/src/php.tar.gz http://192.168.20.252/src/cmake.tar.gz http://192.168.20.252/src

libevent源码分析-TCP服务端代码

先贴一段代码再说,Linux下使用g++ -g-o server server.c -levent 可以直接使用gdb调试,而且可以跟踪到libevent的库里. 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h

libevent 信号事件实现方式

学会使用libevent,才能真正的掌握其是实现原理,我们先从一个简短的测试用例开始: 1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <sys/queue.h> 4 #include <unistd.h> 5 #include <sys/time.h> 6 7 #include <signal.h> 8 #include <fcntl.h> 9 #i

libevent for qt的讨论

一直对Qt官方的QtNetwork模块抱有遗憾,Qt自带的网络模块用的是select模型,无法支持高并发的服务器开发.最近在网上看到有个libevent for qt的东西,它直接替换了Qt的select模型,支持epoll模型,所以就支持高并发了.这东西好啊,弥补了Qt的不足,也弥补了我的遗憾.我兴致勃勃的从网上下载了源代码(github地址:https://github.com/sjinks/qt_eventdispatcher_libevent),然后在windows上编译,结果每次都报错