libevent學習一:windows上簡單的libevent例子
這裡開發主要在windows上開發,熟悉的同學可以修改少量程式碼移植到linux上去,由於在windows上方便的原因,學習主要還是在windows上面開發,而且linevent是支援跨平臺的,所以也可以不用太在意。
上一篇我們已經編譯好了libevent,版本是2.1.8,使用的vs 版本是vs2017。
這裡給大家推薦一下:http://www.wangafu.net/~nickm/libevent-book/ ;有能力的可以去libevent的官網(主要是英語能力),官方寫得還是很好很全面的。
這裡我們先了解一下libevent,libevent是一個事件驅動庫,不能僅說它是一個網路庫,在這裡我也作為一個初學者,和大家講一下我的瞭解,後面會持續更新。
現在我們就把libevent當成支援網路通訊的事件驅動庫,來實現一個簡單的libevent服務客戶端程式:
客戶端:
流程:
1、載入套接字型檔 (windows的socket通訊基礎可以知道);
2、連線服務端;
3、初始化一個event_base物件,建立一個event物件,將socket和處理接收輸出的回撥函式賦通過event_new賦值給event物件,然後將event物件加入事件迴圈;
4、建立一個執行緒,接收介面輸入傳送給服務端;
5、開啟事件迴圈;
6、關閉wsa。
程式碼:
#include "stdafx.h" #include <string.h> #include <errno.h> #include <stdio.h> #include "event2/bufferevent.h" #include "event2/buffer.h" #include "event2/listener.h" #include "event2/util.h" #include "event2/event.h" #include <event2/event-config.h> #include <WinSock2.h> #include <iostream> #define IP_ADDRESS ("127.0.0.1") #define PORT (9951) int m_isrun = 0; int tcp_connect_server(const char* server_ip, int port); void cmd_msg_cb(int fd, char* msg); void socket_read_cb(int fd, short events, void *arg); DWORD WINAPI Fun1Proc(LPVOID lpParameter) { char t_cin[1024]; int sockfd = (int)lpParameter; while (1) { memset(t_cin, 0, 1024); std::cin >> t_cin; if (strcmp(t_cin, "exit") == 0) { break; } cmd_msg_cb(sockfd, t_cin); } exit(1); return 0; } int main(int argc, char** argv) { //載入套接字型檔 WSADATA wsaData; int iRet = 0; iRet = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iRet != 0) { return -1; } if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion)) { WSACleanup(); return -1; } //兩個引數依次是伺服器端的IP地址、埠號 int sockfd = tcp_connect_server(IP_ADDRESS, PORT); 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); //建立執行緒傳送資料 HANDLE hThread1 = CreateThread(NULL, 0, Fun1Proc, (void*)sockfd, 0, NULL); CloseHandle(hThread1); event_base_dispatch(base); WSACleanup(); printf("finished \n"); return 0; } void cmd_msg_cb(int fd, char* msg) { //把終端的訊息傳送給伺服器端 int ret = send(fd, (const char*)msg, strlen((char*)msg), 0); if (ret <= 0) { perror("read fail "); return; } printf("send:%s\n", (char*)msg); } void socket_read_cb(int fd, short events, void *arg) { char msg[1024]; //為了簡單起見,不考慮讀一半資料的情況 int len = recv(fd, msg, sizeof(msg) - 1, 0); if (len <= 0) { perror("read fail "); exit(1); } msg[len] = '\0'; printf("recv %s from server\n", msg); } int tcp_connect_server(const char* server_ip, int port) { int sockfd, status, save_errno; SOCKADDR_IN server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(server_ip); server_addr.sin_port = htons(port); sockfd = ::socket(PF_INET, SOCK_STREAM, 0); if (sockfd == -1) return sockfd; status = ::connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (status == -1) { save_errno = errno; //清理 closesocket(sockfd); errno = save_errno; //the close may be error return -1; } evutil_make_socket_nonblocking(sockfd); return sockfd; }
服務端:
流程:
1、載入套接字型檔
2、初始化tcp的socket,監聽繫結埠;
3、建立event_base和event物件,將等待連線的回撥函式和socket賦值給event物件,然後加入事件迴圈,開始事件迴圈;
4、關閉套接字型檔。
程式碼:
#include<stdio.h> #include<string.h> #include<errno.h> #include <signal.h> #include "event2/bufferevent.h" #include "event2/buffer.h" #include "event2/listener.h" #include "event2/util.h" #include "event2/event.h" #include <event2/event-config.h> #include <WinSock2.h> #define IP_ADDRESS ("127.0.0.1") #define PORT (9951) 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) { //載入套接字型檔 WSADATA wsaData; int iRet = 0; iRet = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iRet != 0) { //cout << "WSAStartup(MAKEWORD(2, 2), &wsaData) execute failed!" << endl;; return -1; } if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion)) { WSACleanup(); //cout << "WSADATA version is not correct!" << endl; return -1; } int listener = tcp_server_init(PORT, 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); WSACleanup(); 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 = recv(fd, msg, sizeof(msg) - 1, 0); if (len <= 0) { printf("some error happen when read\n"); event_free(ev); closesocket(fd); return; } msg[len] = '\0'; printf("recv the client msg: %s\n", msg); char reply_msg[4096] = "I have recvieced the msg: "; strcat(reply_msg + strlen(reply_msg), msg); int ret = send(fd, reply_msg, strlen(reply_msg), 0); } int tcp_server_init(int port, int listen_num) { int errno_save; int 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, (struct sockaddr*)&sin, sizeof(sin)) < 0) { errno_save = errno; evutil_closesocket(listener); errno = errno_save; return -1; } if (::listen(listener, listen_num) < 0) { errno_save = errno; evutil_closesocket(listener); errno = errno_save; return -1; } //跨平臺統一介面,將套接字設定為非阻塞狀態 evutil_make_socket_nonblocking(listener); return listener; }
相關推薦
libevent學習一:windows上簡單的libevent例子
這裡開發主要在windows上開發,熟悉的同學可以修改少量程式碼移植到linux上去,由於在windows上方便的原因,學習主要還是在windows上面開發,而且linevent是支援跨平臺的,所以也可以不用太在意。 上一篇我們已經編譯好了libevent,
TestLink學習一:Windows搭建Apache+MySQL+PHP環境
左右 mysql數據庫 uri 成了 -h 時區 站點 ngx php_curl PHP集成開發環境有很多,如XAMPP、AppServ......只要一鍵安裝就把PHP環境給搭建好了。但這種安裝方式不夠靈活,軟件的自由組合不方便,同時也不利於學習。所以我還是喜歡手工搭建
機器學習備註:Windows上執行Mask_RCNN模型
這些模型在Linux上執行比較方便,不過想起Windows便捷的各種工具,總是忍不住弄過來, 原模型的地址在這, https://github.com/matterport/Mask_RCNN 需要用到的工具pycocotools在這 不過要注意,這個pycocotool
RabbitMQ的學習(一):Windows下安裝及配置RabbitMQ,erlang環境變數
前言:從本章開始,慢慢去了解並深化架構師成長路上所需要的基礎框架:訊息中介軟體; 從這裡開始,會一直往下學習,從what to do到how to do 到why to do。先學會如何使用中介軟體,到後面慢慢去體會中介軟體原理及精髓,然後到最後自己再搭建一個簡單的中介軟體框架。這是該分類的
JBPM學習(一):實現一個簡單的工作流例子全過程
最近發現這篇文章挺多人看的,也挺多人有疑問,我很想幫你們解答,但是很無奈,這篇文章只是我當時在自學時看的一個教程的記錄,當時對JBPM也沒有深入去學習,並且到現在也已經快4年了,這期間我都沒用過JBPM
python django學習一:簡單註冊/登陸/session
rfi bmi ews exception eth mar %u objects 未使用 註冊 登陸 session user.html 未使用{{useform}}而使用{{ userform.password }}形式便於後期css樣式 <!DOCTYPE htm
libevent學習之一:libevent原始碼的特點和結構
1.特點 Libevent是一個用於開發可擴充套件性網路伺服器的基於事件驅動(event-driven)模型的網路庫。Libevent有幾個顯著的特點: (1)事件驅動(event-driven),高效能; (2)輕量級,專注於網路,不如 ACE 那麼臃腫龐大; (3)原始碼
深度學習一:搭建簡單的全連線神經網路
深度學習一:搭建簡單的全連線神經網路 新手入門學習神經網路,嘗試搭建淺層的全連線神經網路,廢話不多說,上主題(文章左後會貼上全部程式碼): 實驗環境:Python3+Pycharm 一個神經網路分為輸入層、隱藏和輸出層,先實現一個單隱藏層的神經網路,輸入為隨機向量x,通過神經網路,擬合隨機
EF6學習筆記一:code-first簡單創建數據庫、表的一些過程
time img install 類名 開啟 屬性 bject nbsp 程序包管理 我的EF學習筆記是按照 汪鵬(網名Jeffcky) 大俠《你必須掌握的Entity Framework 6.x與Core 2.0》來弄的。 這也是我第一篇博客,感覺這東西不能亂寫啊,算
EF6學習筆記一:code-first簡單建立資料庫、表的一些過程
我的EF學習筆記是按照 汪鵬(網名Jeffcky) 大俠《你必須掌握的Entity Framework 6.x與Core 2.0》來弄的。 這也是我第一篇部落格,感覺這東西不能亂寫啊,算了,幹吧。 EF我之前是做過的,但是隻是一些零碎的東西,不成系統。 EF是什麼呢?ORM框架objec
Linux學習筆記(一):Win10上用VMware虛擬機器安裝Linux-CentOS
這周開始Linux的學習,教材參考鳥哥的Linux私房菜,系統本來想用UBUNTU,不過為了方便還是使用教材推薦的CENTOS,下面附上自己的安裝過程。一、 VMware簡介:VMware是一個虛擬PC的軟體,可以在現有的操縱系統上虛擬出一個新的硬體環境,相當於模擬出一臺新的
Python 新手實戰之機器學習實現簡單驗證碼識別(一):用PIL簡單繪製驗證碼
驗證碼生成 from PIL import Image, ImageDraw, ImageFont import random, os def draw(): #隨機生成背景顏色 (RGB顏色範圍為0-255,越高越接近白色),背景顏色不宜過深,
Android多媒體學習一:Android中Image的簡單例項。
在多媒體應用中,Image是最基礎的功能模組,接下來我們將看看在Android中是如何獲取和儲存Image的。Android內嵌的Image獲取和儲存功能,可以讓我們對於整個媒體框架有個比較全面的瞭解,同時為audio和video的學習打下基礎。 一、Image的獲取可以通過
MongoDB的學習與應用一:安裝並簡單測試MongoDB
Document DatabaseA record in MongoDB is a document, which is a data structure composed of field and value pairs. MongoDB documents are similar to JSON obje
Apollo學習(一):在本地Windows系統下搭建Apollo配置中心
說明 在學習Spring Cloud時,學習了Spring Cloud Config作為配置中心來實現微服務例項的配置。但是由於Config自身的侷限性,公司採用了攜程的Apollo作為配置中心,於是通過官方文件和網上資料進行了學習,在這裡進行記錄總結下。 正文
FiddlerScript學習一:改動Request或Response
directed author use lock 改變 請求 including ogl cookies 前兩天因項目須要,簡單看了一下FiddlerScript,功能挺強的。今天有時間細致看一下,做個筆記。 改動Request或Response 改動Request和R
WPF學習一:XAML的資源(Resources)結構
pac logs value 改變 linear sha -a writer arp 一個初學者,把知識做個積累,如果有不對的地方,還請高手指出,謝謝! 先看一段代碼:(下面是以Window WPF進行講解,如果是Web 的話就把<Window改為<Page 而
tomcat源碼學習一:導入eclipse
tps trunk 沒有 asf rop base https distrib 打開 一、下載源碼 進入官網http://tomcat.apache.org,點擊Download>tomcat9>Source Code Distributions>zip
前端知識學習一 :CSS基礎
分隔 color html元素 http 方式 瀏覽器 單位 工作 分離 一.CSS概述 css指的是層疊樣式表,樣式定義如何顯示HTML元素,樣式通常存儲在樣式表中, 把樣式添加到HTML4.0中,是為了解決內容和表現分離的問題。外部樣式表通常存儲在css文件
Spring boot 學習一: 認識Spring boot
XML 過程 maven 認識 很多 團隊 但是 日誌文件 pivotal 什麽是spring boot Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人