Libevent使用例子,從簡單到複雜
本文從簡單到複雜,展示如何使用libevent。網上的許多例子都是隻有伺服器端的,本文裡面客戶端和伺服器端都有,以饗讀者。
關於libevent程式設計時的一些疑問可以閱讀《libevent程式設計疑難解答》。假如讀者還想了解libevent的具體實現,可以閱讀《libevent原始碼分析》系統文章。
不說這麼多了,直接上程式碼。
初等:
客戶端程式碼:
#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/util.h> int tcp_connect_server(const char* server_ip, int port); void cmd_msg_cb(int fd, short events, void* arg); void socket_read_cb(int fd, short events, void *arg); int main(int argc, char** argv) { if( argc < 3 ) { printf("please input 2 parameter\n"); return -1; } //兩個引數依次是伺服器端的IP地址、埠號 int sockfd = tcp_connect_server(argv[1], atoi(argv[2])); if( sockfd == -1) { perror("tcp_connect error "); return -1; } printf("connect to server successful\n"); struct event_base* base = event_base_new(); struct event *ev_sockfd = event_new(base, sockfd, EV_READ | EV_PERSIST, socket_read_cb, NULL); event_add(ev_sockfd, NULL); //監聽終端輸入事件 struct event* ev_cmd = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, cmd_msg_cb, (void*)&sockfd); event_add(ev_cmd, NULL); 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 "); exit(1); } int sockfd = *((int*)arg); //把終端的訊息傳送給伺服器端 //為了簡單起見,不考慮寫一半資料的情況 write(sockfd, msg, ret); } void socket_read_cb(int fd, short events, void *arg) { char msg[1024]; //為了簡單起見,不考慮讀一半資料的情況 int len = read(fd, msg, sizeof(msg)-1); if( len <= 0 ) { perror("read fail "); exit(1); } msg[len] = '\0'; printf("recv %s from server\n", msg); } typedef struct sockaddr SA; int tcp_connect_server(const char* server_ip, int port) { int sockfd, status, save_errno; struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr) ); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); status = inet_aton(server_ip, &server_addr.sin_addr); if( status == 0 ) //the server_ip is not valid value { errno = EINVAL; return -1; } sockfd = ::socket(PF_INET, SOCK_STREAM, 0); if( sockfd == -1 ) return sockfd; status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) ); if( status == -1 ) { save_errno = errno; ::close(sockfd); errno = save_errno; //the close may be error return -1; } evutil_make_socket_nonblocking(sockfd); return sockfd; }
伺服器端程式碼:
#include<stdio.h> #include<string.h> #include<errno.h> #include<unistd.h> #include<event.h> void accept_cb(int fd, short events, void* arg); void socket_read_cb(int fd, short events, void *arg); int tcp_server_init(int port, int listen_num); int main(int argc, char** argv) { int listener = tcp_server_init(9999, 10); if( listener == -1 ) { perror(" tcp_server_init error "); return -1; } struct event_base* base = event_base_new(); //新增監聽客戶端請求連線事件 struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST, accept_cb, base); event_add(ev_listen, NULL); event_base_dispatch(base); return 0; } void accept_cb(int fd, short events, void* arg) { evutil_socket_t sockfd; struct sockaddr_in client; socklen_t len = sizeof(client); sockfd = ::accept(fd, (struct sockaddr*)&client, &len ); evutil_make_socket_nonblocking(sockfd); printf("accept a client %d\n", sockfd); struct event_base* base = (event_base*)arg; //僅僅是為了動態建立一個event結構體 struct event *ev = event_new(NULL, -1, 0, NULL, NULL); //將動態建立的結構體作為event的回撥引數 event_assign(ev, base, sockfd, EV_READ | EV_PERSIST, socket_read_cb, (void*)ev); event_add(ev, NULL); } void socket_read_cb(int fd, short events, void *arg) { char msg[4096]; struct event *ev = (struct event*)arg; int len = read(fd, msg, sizeof(msg) - 1); if( len <= 0 ) { printf("some error happen when read\n"); event_free(ev); close(fd); return ; } msg[len] = '\0'; printf("recv the client msg: %s", msg); char reply_msg[4096] = "I have recvieced the msg: "; strcat(reply_msg + strlen(reply_msg), msg); write(fd, reply_msg, strlen(reply_msg) ); } typedef struct sockaddr SA; int tcp_server_init(int port, int listen_num) { int errno_save; evutil_socket_t listener; listener = ::socket(AF_INET, SOCK_STREAM, 0); if( listener == -1 ) return -1; //允許多次繫結同一個地址。要用在socket和bind之間 evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; sin.sin_port = htons(port); if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 ) goto error; if( ::listen(listener, listen_num) < 0) goto error; //跨平臺統一介面,將套接字設定為非阻塞狀態 evutil_make_socket_nonblocking(listener); return listener; error: errno_save = errno; evutil_closesocket(listener); errno = errno_save; return -1; }
中等:
客戶端程式碼:
#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(struct bufferevent* bev, void* arg); void event_cb(struct bufferevent *bev, short event, void *arg); int main(int argc, char** argv) { if( argc < 3 ) { printf("please input 2 parameter\n"); return -1; } //兩個引數依次是伺服器端的IP地址、埠號 int sockfd = tcp_connect_server(argv[1], atoi(argv[2])); if( sockfd == -1) { perror("tcp_connect error "); return -1; } printf("connect to server successful\n"); struct event_base* base = event_base_new(); struct bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE); //監聽終端輸入事件 struct event* ev_cmd = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, cmd_msg_cb, (void*)bev); event_add(ev_cmd, NULL); //當socket關閉時會用到回撥引數 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 "); exit(1); } struct bufferevent* bev = (struct bufferevent*)arg; //把終端的訊息傳送給伺服器端 bufferevent_write(bev, msg, ret); } void server_msg_cb(struct bufferevent* bev, void* arg) { char msg[1024]; size_t len = bufferevent_read(bev, msg, sizeof(msg)); msg[len] = '\0'; printf("recv %s from server\n", msg); } void event_cb(struct 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"); //這將自動close套接字和free讀寫緩衝區 bufferevent_free(bev); struct event *ev = (struct event*)arg; //因為socket已經沒有,所以這個event也沒有存在的必要了 event_free(ev); } typedef struct sockaddr SA; int tcp_connect_server(const char* server_ip, int port) { int sockfd, status, save_errno; struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr) ); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); status = inet_aton(server_ip, &server_addr.sin_addr); if( status == 0 ) //the server_ip is not valid value { errno = EINVAL; return -1; } sockfd = ::socket(PF_INET, SOCK_STREAM, 0); if( sockfd == -1 ) return sockfd; status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) ); if( status == -1 ) { save_errno = errno; ::close(sockfd); errno = save_errno; //the close may be error return -1; } evutil_make_socket_nonblocking(sockfd); return sockfd; }
伺服器端程式碼:
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<event.h>
#include<event2/bufferevent.h>
void accept_cb(int fd, short events, void* arg);
void socket_read_cb(bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int tcp_server_init(int port, int listen_num);
int main(int argc, char** argv)
{
int listener = tcp_server_init(9999, 10);
if( listener == -1 )
{
perror(" tcp_server_init error ");
return -1;
}
struct event_base* base = event_base_new();
//新增監聽客戶端請求連線事件
struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
accept_cb, base);
event_add(ev_listen, NULL);
event_base_dispatch(base);
event_base_free(base);
return 0;
}
void accept_cb(int fd, short events, void* arg)
{
evutil_socket_t sockfd;
struct sockaddr_in client;
socklen_t len = sizeof(client);
sockfd = ::accept(fd, (struct sockaddr*)&client, &len );
evutil_make_socket_nonblocking(sockfd);
printf("accept a client %d\n", sockfd);
struct event_base* base = (event_base*)arg;
bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg);
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));
msg[len] = '\0';
printf("recv the client msg: %s", msg);
char reply_msg[4096] = "I have recvieced the msg: ";
strcat(reply_msg + strlen(reply_msg), msg);
bufferevent_write(bev, reply_msg, strlen(reply_msg));
}
void event_cb(struct 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");
//這將自動close套接字和free讀寫緩衝區
bufferevent_free(bev);
}
typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{
int errno_save;
evutil_socket_t listener;
listener = ::socket(AF_INET, SOCK_STREAM, 0);
if( listener == -1 )
return -1;
//允許多次繫結同一個地址。要用在socket和bind之間
evutil_make_listen_socket_reuseable(listener);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port);
if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
goto error;
if( ::listen(listener, listen_num) < 0)
goto error;
//跨平臺統一介面,將套接字設定為非阻塞狀態
evutil_make_socket_nonblocking(listener);
return listener;
error:
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save;
return -1;
}
高等:
客戶端程式碼:
#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(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int main(int argc, char** argv)
{
if( argc < 3 )
{
//兩個引數依次是伺服器端的IP地址、埠號
printf("please input 2 parameter\n");
return -1;
}
struct event_base *base = event_base_new();
struct bufferevent* bev = bufferevent_socket_new(base, -1,
BEV_OPT_CLOSE_ON_FREE);
//監聽終端輸入事件
struct event* ev_cmd = event_new(base, STDIN_FILENO,
EV_READ | EV_PERSIST,
cmd_msg_cb, (void*)bev);
event_add(ev_cmd, NULL);
struct 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, (struct 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 ");
exit(1);
}
struct bufferevent* bev = (struct bufferevent*)arg;
//把終端的訊息傳送給伺服器端
bufferevent_write(bev, msg, ret);
}
void server_msg_cb(struct bufferevent* bev, void* arg)
{
char msg[1024];
size_t len = bufferevent_read(bev, msg, sizeof(msg));
msg[len] = '\0';
printf("recv %s from server\n", msg);
}
void event_cb(struct 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("the client has connected to server\n");
return ;
}
//這將自動close套接字和free讀寫緩衝區
bufferevent_free(bev);
struct event *ev = (struct event*)arg;
event_free(ev);
}
伺服器端程式碼:
#include<netinet/in.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<event.h>
#include<listener.h>
#include<bufferevent.h>
#include<thread.h>
void listener_cb(evconnlistener *listener, evutil_socket_t fd,
struct 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()
{
//evthread_use_pthreads();//enable threads
struct sockaddr_in sin;
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(9999);
event_base *base = event_base_new();
evconnlistener *listener
= evconnlistener_new_bind(base, listener_cb, base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
10, (struct sockaddr*)&sin,
sizeof(struct sockaddr_in));
event_base_dispatch(base);
evconnlistener_free(listener);
event_base_free(base);
return 0;
}
//一個新客戶端連線上伺服器了
//當此函式被呼叫時,libevent已經幫我們accept了這個客戶端。該客戶端的
//檔案描述符為fd
void listener_cb(evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sock, int socklen, void *arg)
{
printf("accept a client %d\n", fd);
event_base *base = (event_base*)arg;
//為這個客戶端分配一個bufferevent
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 has 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");
//這將自動close套接字和free讀寫緩衝區
bufferevent_free(bev);
}
相關推薦
Libevent使用例子,從簡單到複雜
本文從簡單到複雜,展示如何使用libevent。網上的許多例子都是隻有伺服器端的,本文裡面客戶端和伺服器端都有,以饗讀者。 關於libevent程式設計時的一些疑問可以閱讀《libevent程式設計疑難解答》。假如讀者還想了解libe
Libevent使用例子,從簡單到復雜
enable targe 描述 har ron 請求 got memset repl 轉載請註明出處:http://blog.csdn.net/luotuo44/article/details/39670221 本文從簡單到復雜,展示如何使用l
libevent學習,從3個例子開始
dispatch 引用 復雜 printf tin details serve fin reply 最近一直在ubuntu下研究c++開源代碼,本文的內容是大名鼎鼎的libevent庫。 本文將從3個例子著手,從簡單到復雜,分別包含了client與server。 文章參考該
高亮:單關鍵詞、多關鍵詞、多組多關鍵詞,從簡單到複雜實現滿足多方面需求的頁面關鍵詞高亮
前言 我的前言都是良心話,還是姑且看一下吧: 別人一看這個標題,心想,“怎麼又是一個老到掉牙的需求,網上一搜一大堆解決方案啦!”。沒錯!這個需求實在老土得不能再老土了,我真不想寫這樣一種需求的文章,無奈!無奈! 現實的情況是我想這麼舊的需求網上資料一大把一大把,雖然我知道網上資料可能有坑,但是我總不信找
理解神經網路,從簡單的例子開始(2)使用python建立多層神經網路
這篇文章將講解如何使用python建立多層神經網路。在閱讀這篇文章之前,建議先閱讀上一篇文章:理解神經網路,從簡單的例子開始。講解的是單層的神經網路。如果你已經閱讀了上一篇文章,你會發現這篇文章的程式碼和上一篇基本相同,理解起來也相對容易。 上一篇文章使用了9
Web API,從簡單型別到複雜型別的引數傳遞用例,以及傳遞簡單string型別的解決辦法
http://www.cnblogs.com/kvspas/p/3384448.html 一,簡單型別的傳值 比如 public Users Get(int id) ,它可以使用兩種方式獲取: api/default/5$.get("/api/default",{id
LFU五種實現方式,從簡單到複雜
## 前言 最近刷力扣題,對於我這種 0 基礎來說,真的是腦殼疼啊。這個月我估計都是中等和困難題,沒有簡單題了。 幸好,力扣上有各種大牛給寫題解。看著他們行雲流水的程式碼,真的是羨慕不已。讓我印象最深刻的就是人稱 “甜姨” 的知心姐姐,還有名叫威哥的大哥。幾乎每天他們的題解我都是必看的。 甜姨的題解,雖
npm install —— 從一個簡單例子,看本地安裝與全域性安裝的區別
npm的包安裝分為本地安裝(local)、全域性安裝(global)兩種,從敲的命令列來看,差別只是有沒有-g而已,比如 npm install grunt # 本地安裝 npm install -g grunt-cli # 全域性安裝 這兩種安裝方式有什麼區別呢?從
(MySQL)從簡單例子到複雜例子認識MySQL
本文將簡單介紹MySQL和彙集一些常見例子來幫大家理解sql語句,可以當做字典檢視。(前排提示,因為我是先在onenote做一次筆記,在來發blog的,但從onenote複製的內容會變成圖片,所以可能畫面有點奇怪,不過不影響學習哈哈)提綱:資料庫簡介0.MySQL使用1.資料
#鑑別程式設計師是大牛還是小白?網友:簡單,從髮量就可以看出啊
程式設計師的技術高低是由什麼決定的呢?是有你的工作年限,還是你的專案經驗?我覺得都可以作為一個判斷依據,其中還有一個是什麼?沒錯,聰明的小夥伴已經猜出來了,就是你的發亮。 有網友在釋出了一個如何鑑別菜鳥和大神程式設計師的帖子,原貼是這樣的: 在這裡我推薦下自己整理的資料,我自己是一名從事
Python陣列取一個或幾個元素值的例子,word[0:2],從第0個字元到第2個字元(不包括第2個字元)
https://docs.python.org/3/tutorial/introduction.html#strings >>> word = 'Python' >>> word[0] # character in position 0 'P'
一個從右向左遞增,從上到下遞增的二位資料矩陣,怎麼用演算法複雜度O(n)的演算法來查詢其中的某一個數
import java.util.Scanner; /** * */ /** * @author jueying: * @version 建立時間:2018-10-21 下午04:03:54 * 類說明 */ /** * @author jueying
簡單三步,從零開始做自媒體,新手快速上手
對於很多人來說想要做自媒體,從過這個平臺為自己獲取一份額外的收入,但是在這無數的自媒體人中有的人收入可觀,而有的人做了一段時間就給放棄了,覺得沒有流量收益又浪費時間。那麼對於我們很多剛接觸還是已經在做的如何才能做自媒體呢?簡單來說可以分為三個步驟 選擇領域在進行好最基本的媒體賬戶註冊之後,我們首先就是需要選
mongodb 中的 map reduce 的快速入門例子,簡單操作和理解。
先看下mongodb官方給出的例子的圖。 個人理解的解釋: 這個圖,有四列資料。 第一列:原始資料。通常對應的mongodb裡面的一個表collection。 第二列:經過某些條件過濾過的資料,這個圖裡面就是按{"status":"A"}過濾資料。這個過濾的條件對應上面程式
python3傳送郵件02(簡單例子,帶附件)
#!/usr/bin/env python# -*- coding:UTF-8 -*- import osimport smtplibfrom email.header import Headerfrom email.mime.text import MIMETextfrom email.mime.mult
理解HashMap底層原理,一個簡單的HashMap例子
amp builder out print node get bject sta value package com.jl.testmap; /** * 自定義一個HashMap * @author JiangLai * */ public c
從零開始,編寫簡單的課程資訊管理系統(使用jsp+servlet+javabean架構)
一、相關的軟體下載和環境配置 1、下載並配置JDK。 2、下載eclipse。 3、下載並配置apache-tomcat(伺服器)。 4、下載MySQL(資料庫)。 5、下載Navicat for MySQL(資料庫視覺化工具),方便對資料庫的操作。 6、下載jdbc用來實現eclipse中的專案
一個簡單的例子,帶你理解haproxy!
如果你對haproxy啥都不懂,這篇文章將對你有很大的幫助。大神請繞行! haproxy是一個性能不輸於nginx的工具。和nginx功能類似,可以實現負載均衡。他與nginx不同的是,haproxy既可以實現基於http的七層架構,又可以實現基於tcp/udp的四層架構。 [[email&
springboot整合activemq簡單例子,附上原始碼連結
在springboot的官網拿到工程,並且匯入activeMq的依賴 application.properties檔案 spring.activemq.broker-url=tcp://192.168.66.43:61616 spring.activemq.in-m
無需複雜的數學描述,通過簡單程式碼理解卷積模組
選自 towardsdatascience,作者:Paul-Louis Pröve,機器之心編譯,參與:Panda。 比起晦澀複雜的數學或文字描述,也許程式碼能幫助我們更好地理解各種卷積模組。電腦科學家 Paul-Louis Pröve 用 Keras 對瓶頸模組、Inception 模組、殘差模組