LINUX.ORG.RU

libevent и c++


0

1

Как можно использовать libevent в C++ приложении? Как передать колбеки?

class {
............
static void readcb(struct bufferevent *bev, void *ptr);
static void eventcb(struct bufferevent *bev, short events, void *ptr);
............
}
............
void class::some_method()
{
bufferevent_setcb(this->bev, this->readcb, NULL, this->eventcb, NULL);
}

Можно конечно изобрести чтото вроде этого но думается что знатоки C++ должны подсказать более очевидный метод:

int СtoCPPcb(void* This, void* Method, int Param1, int Param2)
{
	__asm

	{
		mov	ecx,[This];
		push	Param2;
		push	Param1;
		call	[Method];
	}

}

★★★
bufferevent_setcb(this->bev, Class::readcb, NULL, Class::eventcb, this);
static void Class::readcb(struct bufferevent *bev, short events, void *ptr) {
    Class *cl = static_cast<Class *>(ptr);
    cl->do_real_readcb(bev, events);
}
yoghurt ★★★★★
()

Или вместо использования статических методов можно написать маленький хелпер со статическим методом.

kulti ★★
()
Ответ на: комментарий от yoghurt

чтото данный метод не отличается работоспособностью. все такая же тишина колбеки не вызываются.

TheMixa ★★★
() автор топика
Ответ на: комментарий от kulti

>Или вместо использования статических методов можно написать маленький хелпер со статическим методом.

интересно былобы посмотреть

TheMixa ★★★
() автор топика

очевидно, что в качестве пользователских данных в колбек надо передавать this.

Reset ★★★★★
()
Ответ на: комментарий от Reset

так дело в нем том что передавать, дело в том что колбек даже не вызывается

TheMixa ★★★
() автор топика
Ответ на: комментарий от placement_new

>Очевидно проблема не в организации коллбеков, а в неверном использовании libevent.

А как верно использовать?

Берем рабочий код на C(даже для верности возьмем из libevent-book-2.11) и заворачиваем его в класс C++, всю инициализацию запихиваем в конструктор, колбеки статическими(как по другому?) методами класса, dispatch запускаем из конструктора или вообще из вне класса.

TheMixa ★★★
() автор топика
Ответ на: комментарий от Reset

Вот взял рабочий пример из официального мануала, проверил что работает и завернул в класс(ну инклюды только в майне лишние есть). Пробовал к нему применять вышеназванные советы результат не изменился.

evsocket.h

#ifndef EVSOCKET_H
#define EVSOCKET_H

class evsocket {

public:
	evsocket(/*in_addr_t*/ char *addr, in_port_t port);
	~evsocket();
	
	void setaddr(in_addr_t addr, in_port_t port, sa_family_t family = PF_INET);
	void setaddr(char *addr, in_port_t port, sa_family_t family = PF_INET);
	struct event_base *base;

private:
	struct bufferevent *bev;
	struct sockaddr_in sin;
	
	static void readcb(struct bufferevent *bev, void *ptr);
	static void eventcb(struct bufferevent *bev, short events, void *ptr);
	void runsocket();
};

#endif // EVSOCKET_H
evsocket.cpp
#include <arpa/inet.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include "evsocket.h"

evsocket::evsocket(/*in_addr_t*/ char *addr, in_port_t port)
{
	this->setaddr(addr, port);
	this->runsocket();
}

evsocket::~evsocket()
{
	bufferevent_free(this->bev);
	event_base_loopexit(this->base, NULL);
}

void evsocket::setaddr(in_addr_t addr, in_port_t port, sa_family_t family)
{
	this->sin.sin_family = family;
	this->sin.sin_addr.s_addr = addr;
	this->sin.sin_port = port;
}

void evsocket::setaddr(char *addr, in_port_t port, sa_family_t family)
{
	this->sin.sin_family = family;
	inet_aton(addr, &this->sin.sin_addr);
}

void evsocket::readcb(struct bufferevent *bev, void *ptr)
{
	char buf[1024];
    int n;
    struct evbuffer *input = bufferevent_get_input(bev);
	//call ondata
    while ((n = evbuffer_remove(input, buf, sizeof(buf))) > 0) {
        fwrite(buf, 1, n, stdout);
    }
}

void evsocket::eventcb(struct bufferevent *bev, short events, void *ptr)
{
	if (events & BEV_EVENT_CONNECTED)
	{
		//call onevent
		printf("Connected\n");
	}
	else if (events & (BEV_EVENT_ERROR | BEV_EVENT_EOF))
	{
		if (events & BEV_EVENT_ERROR)
		{
			//call onevent
			perror("Event error");
		}
		printf("Need to destroy\n");
		//destroy
	}
}

void evsocket::runsocket()
{
	this->base = event_base_new();
	this->bev = bufferevent_socket_new(this->base, -1, BEV_OPT_CLOSE_ON_FREE);
	bufferevent_setcb(this->bev, this->readcb, NULL, this->eventcb, this);
	bufferevent_enable(this->bev, EV_READ|EV_WRITE);
	evbuffer_add_printf(bufferevent_get_output(bev), "GET %s\r\n", "/");
	if(bufferevent_socket_connect(this->bev, (struct sockaddr *)&this->sin, sizeof(this->sin)) == -1)
		perror("Connect fail:");
	//else
		//event_base_dispatch(this->base);
}
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include "evsocket.h"

int main(int argc, char **argv) {
	
	evsocket http_req = evsocket("74.125.79.147",80);
	event_base_dispatch(http_req.base);
	return 0;
}

TheMixa ★★★
() автор топика
Ответ на: комментарий от TheMixa

ога, у меня callback вызывался с connection refused так как я на локалхост ломился :) а у тебя пакеты drop'ались, поэтому оно бы вызвалось только по таймауту

Reset ★★★★★
()

бля везде одно this->
жаблокодер на с++ детектед
пиздуйде в свою яву и пишите там херню

ps а по делу, нет смысла писать какието гомнообертки
проще разобратся во всей libevent и переписать свою на чистом C++

anonymous
()
Ответ на: комментарий от anonymous

годный вброс.

если что явы даже не знаю. про this еще вот перед анонимусами не отчитывался.

про переписать ну просто бугага. если что следуя твоей логике надо использовать libev.

ps по делу уже все решено и закрыто. троли в другом месте.

TheMixa ★★★
() автор топика
Ответ на: комментарий от TheMixa

Если есть boost::bind или (std::tr1::bind), то типа такого:

class LibEventHelper
{
  public:
    typedef boost::function<...> LibEventCallback;
    LibEventHelper(LibEventCallback readCb) : readCb(readCb)
    {
      ...
    };

  private
    LibEventCallback readCb;

    static void readcb(struct bufferevent *bev, void *ptr)
    {
      LibEventHelper* thisPtr = reinterpret_cast<LibEventHelper*>(ptr);
      ptr->readCb(bev);
    }
};

Если bind'а нет, то мини-велосипед:

template<class T>
class LibEventHelper
{
  public:
    typedef void(T::* LibEventCallback)();
    LibEventHelper(T* object, LibEventCallback readCb) : object(object), readCb(readCb)
    {
      ...
    };

  private
    T* object;
    LibEventCallback readCb;

    void runCb(struct bufferevent *bev){object->*readCb(bev);}
    static void readcb(struct bufferevent *bev, void *ptr)
    {
      LibEventHelper* thisPtr = reinterpret_cast<LibEventHelper*>(ptr);
      ptr->runCb(bev);
    }
};

kulti ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.