1. 程式人生 > 實用技巧 >bufferevent客戶端傳送檔案並處理超時和斷開事件

bufferevent客戶端傳送檔案並處理超時和斷開事件

demo下載地址

連結:https://pan.baidu.com/s/1j21bCNiXHBSFxk2VUCxK6g
提取碼:v9hn

#include <iostream>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <string.h>
#ifndef _WIN32
#include <signal.h>
#else
#endif
#include <string>
using
namespace std; static string recvstr = ""; static int recvCount = 0; static int sendCount = 0; //錯誤,超時 (連線斷開會進入) void event_cb(bufferevent *be,short events,void *arg) { cout<<"[E]"<<flush; //讀取超時時間發生後,資料讀取停止 if(events & BEV_EVENT_TIMEOUT && events & BEV_EVENT_READING) {
//讀取緩衝中資料 char data[1024] = {0}; //讀取輸入緩衝資料 int len = bufferevent_read(be,data,sizeof(data)-1); if(len>0) { recvCount+= len; recvstr += data; } cout<<"BEV_EVENT_READING BEV_EVENT_TIMEOUT"<<endl; //bufferevent_enable(be,EV_READ);
bufferevent_free(be); cout<<recvstr<<endl; cout<<"recvCount="<<recvCount<<" sendCount="<<sendCount<<endl; } else if(events & BEV_EVENT_ERROR) { bufferevent_free(be); } else { cout<<"OTHERS"<<endl; } } void write_cb(bufferevent *be,void *arg) { cout<<"[W]"<<flush; } void read_cb(bufferevent *be,void *arg) { cout<<"[R]"<<flush; char data[1024] = {0}; //讀取輸入緩衝資料 int len = bufferevent_read(be,data,sizeof(data)-1); //cout<<"["<<data<<"]"<<endl; cout<<data<<flush; if(len<=0)return; recvstr += data; recvCount += len; /*if(strstr(data,"quit") !=NULL) { cout<<"quit"; //退出並關閉socket BEV_OPT_CLOSE_ON_FREE bufferevent_free(be); }*/ //傳送資料 寫入到輸出緩衝 bufferevent_write(be,"OK",3); } void listen_cb(evconnlistener *ev,evutil_socket_t s,sockaddr*sin,int slen,void *arg) { cout<<"listen_cb"<<endl; event_base *base = (event_base *)arg; //建立bufferevent上下文 BEV_OPT_CLOSE_ON_FREE清理bufferevent時關閉socket bufferevent *bev = bufferevent_socket_new(base,s,BEV_OPT_CLOSE_ON_FREE); //新增監控事件 bufferevent_enable(bev,EV_READ|EV_WRITE); //設定水位 //讀取水位 bufferevent_setwatermark(bev,EV_READ, 5, //低水位 0就是無限制 預設是0 10 //高水位 0就是無限制 預設是0 ); bufferevent_setwatermark(bev,EV_WRITE, 5, //低水位 0就是無限制 預設是0 緩衝資料低於5 寫入回撥被呼叫 0 //高水位無效 ); //超時時間的設定 timeval t1 = {0,500000}; bufferevent_set_timeouts(bev,&t1,0); //設定回撥函式 bufferevent_setcb(bev,read_cb,write_cb,event_cb,base); } //錯誤,超時 (連線斷開會進入) void client_event_cb(bufferevent *be,short events,void *arg) { cout<<"[client_E]"<<flush; //讀取超時時間發生後,資料讀取停止 if(events & BEV_EVENT_TIMEOUT && events & BEV_EVENT_READING) { cout<<"BEV_EVENT_READING BEV_EVENT_TIMEOUT"<<endl; //bufferevent_enable(be,EV_READ); bufferevent_free(be); return; } else if(events & BEV_EVENT_ERROR) { bufferevent_free(be); return; } //服務端的關閉事件 if(events & BEV_EVENT_EOF) { cout<<"BEV_EVENT_EOF"<<endl; bufferevent_free(be); } if(events & BEV_EVENT_CONNECTED ) { cout<<"BEV_EVENT_CONNECTED"<<endl; //觸發write bufferevent_trigger(be,EV_WRITE,0); } } void client_write_cb(bufferevent *be,void *arg) { cout<<"[client_W]"<<flush; FILE *fp = (FILE *)arg; char data[1024] = {0}; int len = fread(data,1,sizeof(data)-1,fp); if(len<=0) { //讀到結尾或者檔案出錯 fclose(fp); //立刻清理,可能會造成緩衝資料沒有傳送結束 //bufferevent_free(be); bufferevent_disable(be,EV_WRITE); return; } sendCount += len; //寫入buffer bufferevent_write(be,data,len); } void client_read_cb(bufferevent *be,void *arg) { cout<<"[client_R]"<<flush; } int main(int argc,char *argv[]) { #ifdef _WIN32 //初始化socket庫 WSADATA wsa; WSAStartup(MAKEWORD(2,2),&wsa); #else //忽略管道訊號,傳送資料給已關閉的socket if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return 1; #endif event_base *base = event_base_new(); //建立網路伺服器 //設定監聽的埠和地址 sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(5001); evconnlistener *ev = evconnlistener_new_bind(base, listen_cb, //回撥函式 base, //回撥函式的引數arg LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, 10, //listen back (sockaddr*)&sin, sizeof(sin) ); { //呼叫客戶端程式碼 //-1內部建立socket bufferevent *bev = bufferevent_socket_new(base,-1,BEV_OPT_CLOSE_ON_FREE); sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(5001); evutil_inet_pton(AF_INET,"127.0.0.1",&sin.sin_addr.s_addr); FILE *fp = fopen("test_buffer_client.cpp","rb"); //設定回撥函式 bufferevent_setcb(bev,client_read_cb,client_write_cb,client_event_cb,fp); bufferevent_enable(bev,EV_READ|EV_WRITE); int re = bufferevent_socket_connect(bev,(sockaddr*)&sin,sizeof(sin)); if(re == 0) { cout<<"connected"<<endl; } } //進入事件主迴圈 event_base_dispatch(base); evconnlistener_free(ev); event_base_free(base); return 0; }