libevent C++パッケージ


最近libeventを勉強する過程で、受信データが不完全で、clientからのデータをどのように受信して返信するかなどの多くの問題に遭遇しました.そしてread_についてです.cbはどのように書くべきかという問題を最後にまとめ、クラスにカプセル化し、次にどのように使うかを話します.
ソースファイル:libSocket.h libSocket.cpp MyEvent.h MyEvent.cppという4つのファイルは自分で書いたもので、パッケージの目的はプロセス全体をより明確に理解することです.
以下はlibSocketクラスです.このクラスには2つの関数しかありません.GetFileDescriptionByListenはリスニングです.s_ipはアクセス可能なIPであり、「127.0.0.1」または「0.0.0.0」であり、queueはlistenのキューサイズである.関数は、最終的にリスニング中のファイル記述子を返します.GetFileDescriptionByConnectは接続関数、s_hostは接続するサービス側IPであり、最終的には接続されたファイル記述子を返す.
#ifndef LIBSOCKET_H_
#define LIBSOCKET_H_
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>


using namespace std;

class libSocket {
public:
	libSocket();
	virtual ~libSocket();
	/*    */
	int GetFileDescriptionByListen(const char* s_ip, int16_t port, int queue);
	int GetFileDescriptionByConnect(const char* s_host, int16_t port);
};

#endif /* LIBSOCKET_H_ */

以下はlibSocket.cpp
#include "libSocket.h"

libSocket::libSocket() {
	// TODO Auto-generated constructor stub

}

libSocket::~libSocket() {
	// TODO Auto-generated destructor stub
}

int libSocket::GetFileDescriptionByListen(const char* s_ip,int16_t port,int queue){

	int fd = 0;					/*        */
	sockaddr_in server_addr;

	bzero(&server_addr,sizeof(server_addr));			/*       */
	server_addr.sin_family = AF_INET;					/*  AF_INET     */
	server_addr.sin_addr.s_addr = inet_addr(s_ip);	/*     ,   in_addr   ,INADDR_ANY        IP*/
	server_addr.sin_port = htons(port);					/*   ,          ,       htons()    */

	/*     */
	if ( !(fd = socket(AF_INET,SOCK_STREAM,0)) ){
		cerr << strerror(errno) << endl;
		return -1;
	}

	/*            */
	if ( bind(fd,(sockaddr *)(&server_addr),sizeof(server_addr)) != 0 ){
		cerr << strerror(errno) << endl;
		return -2;
	}

	/*          */
	if ( listen(fd,queue) != 0 ){
		cerr << strerror(errno) << endl;
		return -3;
	}

	return fd;
}

int libSocket::GetFileDescriptionByConnect(const char *host,int16_t port){
	int fd = 0;
	/*                 */
	struct sockaddr_in server_addr;
	/*    gethostbyname     */
	hostent* p_host;

	//    
	if( (p_host = gethostbyname(host)) == NULL ){
		cerr << strerror(errno) << endl;
		return -1;
	}

	//     socket
	if( ( fd = socket(AF_INET,SOCK_STREAM,0) ) < 1 ){
		cerr << strerror(errno) << endl;
		return -2;
	}

	/*       */
	bzero(&server_addr,sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr = *((struct in_addr *)p_host->h_addr);

	/*  TCP  */
	if( connect(fd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)) != 0 ){
		cerr << strerror(errno) << endl;
		return -3;
	}
	return fd;
}

次が主な話だ
MyEvent.h
これも簡単なメンバー関数です
  • BindEventBaseを使用し、使用する前にevent_を作成します.base.
  • CreateEventForListenを使用してネットワークイベントを作成するには、ローカルで傍受するIPとポートを通知する必要があります.この方法の実装では、上記のlibSocketが使用されています.
  • このクラスは親として使用されます.使用する場合は、子クラスに親の3つのメソッドを書き換える必要があります.すなわちCallBackOfRead,CallBackOfWrite,CallBackOfError.
  • #ifndef MYEVENT_H_
    #define MYEVENT_H_
    
    #include <event.h>
    #include "libSocket.h"
    
    
    class MyEvent {
    public:
    	void CreateEventForListen(const char* SrcIPAddress,int16_t ListenPort);
    	void BindEventBase(event_base* base){ this->base = base; } //     
    	event_base* GetEventBase(void);
    
    	/*                    */
    	virtual void CallBackOfRead(bufferevent* bev,void* arg)=0;  //       
    	virtual void CallBackOfWrite(bufferevent* bev,void* arg)=0;	//           
    	virtual void CallBackOfError(bufferevent* bev,short event, void* arg)=0; //                
    
    private:
    	event_base* base;
    };
    
    
    
    
    
    #endif /* MYEVENT_H_ */

    MyEvent.cpp
    #include "MyEvent.h"
    
    void onRead(bufferevent* bev,void* arg){	
    	MyEvent* myevent = (MyEvent*)arg;
    	myevent->CallBackOfRead(bev,arg);
    }
    
    void onWrite(bufferevent* bev,void* arg){	
    	MyEvent* myevent = (MyEvent*)arg;
    	myevent->CallBackOfWrite(bev,arg);
    }
    
    void onError(bufferevent* bev, short event, void* arg){  
    	MyEvent* myevent = (MyEvent*)arg;
    	myevent->CallBackOfError(bev,event,arg);
    }
    
    void onAccept( int fd ,short event, void* arg ){	
    	MyEvent* myevent = (MyEvent*)arg;
    	int client_fd;
    	sockaddr_in client_in;
    	socklen_t client_len = sizeof(client_in);
    	client_fd = accept(fd,(struct sockaddr*)&client_in,&client_len);   //      
    	bufferevent* buffer_ev = bufferevent_socket_new(myevent->GetEventBase(),client_fd,BEV_OPT_CLOSE_ON_FREE);                     //    I/O  
    	bufferevent_setcb(buffer_ev,onRead,onWrite,onError,arg);  //  I/O       
    	bufferevent_enable(buffer_ev,EV_READ | EV_PERSIST);	//    IO
    }
    
    
    event_base* MyEvent::GetEventBase(void){
    	return this->base;
    }
    
    void MyEvent::CreateEventForListen(const char* SrcIPAddress,int16_t ListenPort){ 
    	libSocket* socket = new libSocket();
    	int fd = socket->GetFileDescriptionByListen(SrcIPAddress,ListenPort,1024);
    	if ( !this->base ){
    		cout << "event_base_error" << endl;
    		return ;
    	}
    	event* ev = event_new( this->base , fd , EV_READ | EV_PERSIST, onAccept , this );
    	event_add(ev,NULL);
    }

    次に、MyEventを継承するサブクラスを書きます.
    ここで特に注意したいのは、CallBackOfWrite()の書き換えであり、大量のデータがバッファに転送されると、この関数は複数回トリガーされ、一度にはそんなに多くのデータを受信できない、例えば100000バイトを転送し、その関数をトリガするたびに4000バイト程度しか受信できない可能性があるので、ここで必要な最終データを処理しないでください.ここでは、すべてのデータをコンテナスタックに押し込むか、ローカルに書き込む必要があります.ローカルに書き込む場合は、この関数でファイル記述子を開かないでください.複数回のトリガなので、最終的に得られた結果は小さなブロックになります.ファイル記述子が転送されたと判断できない限り、ここでファイル記述子を閉じることはできません.
    #ifndef TEST_H_
    #define TEST_H_
    #include "MyEvent.h"
    
    class test : public MyEvent {
    public:
    	void CallBackOfRead(bufferevent* bev,void* arg){
    		evbuffer* input = bufferevent_get_input(bev);
    		char buffer[1024];
    		memset(buffer,'\0',sizeof(buffer));
    		int r_len = 0;
    		while ( ( r_len = evbuffer_remove( input, buffer, 1024  ) ) > 0 ){
    			cout << buffer;
    			memset(buffer,'\0',sizeof(buffer));
    			
    	}
    
    	void CallBackOfWrite(bufferevent* bev,void* arg){
    		cout << "write" << endl;
    	}
    
    	void CallBackOfError(bufferevent* bev,short event,void* arg){
    		cout << "error" << endl;
    	}
    };
    
    #endif /* TEST_H_ */

    以下は主関数部分mainである.cpp
    #include <event.h>
    #include <iostream>
    #include "libSocket.h"
    #include "test.h"
    
    
    int main(void){
    	event_base* base = event_base_new();
    	test* MyTest = new test();
    	MyTest->BindEventBase(base);
    	MyTest->CreateEventForListen("0.0.0.0",2111);
    	event_base_dispatch(base);
    	return 0;
    
    }