欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++編寫高性能服務器實例教程

 更新時間:2020年06月01日 14:52:45   作者:慕神8447489  
這篇文章主要介紹了如何用C++編寫高性能服務器,文中通過示例代碼介紹的非常詳細,對大家學習C++有一定的參考價值,需要的朋友們可以了解下

我將展示如何使用現(xiàn)代C++編寫一個Echo服務器,相當于分布式系統(tǒng)開發(fā)中的“Hello World”。這個服務器會將接收的消息直接返回。我們同時需要一個可以向我們的服務器發(fā)動消息的客戶端,在這里可以發(fā)現(xiàn)客戶端的源碼。

Wangle是一個用來搭建事件驅動的現(xiàn)代異步C++服務的C/S應用框架。Wangle最基本的抽象概念就是Pipeline(管線)。能夠理解這種抽象,將會很容易寫出各種復雜的現(xiàn)代C++服務,另一個重要的概念是Service(服務),其可以看作一種更高級的Pipeline,不過超出了本文我們關注的范疇。

PipeLine

pipeline 是 Wangle 中最重要也是最強大的抽象,可以讓用戶在定制 request 和 response 的實現(xiàn)時擁有很大的自由。一個pipeline就是一系列request/response控制程序的嵌套。我試圖尋找一個真實世界中pipeline的類比,唯一我能想到的就是現(xiàn)實世界工廠中的生產線。一條生產線工作在一種順序模式下,所有的工人取得一個物體,并且只添加一種修改,再將其發(fā)送給上游的工人直到整個產品制造完成。這可能不是一個特別好的比喻,因為流水線上產品的流動是單向的,而一個pipeline能控制反方向的數(shù)據(jù)流動--就好像將成品分解成原材料。

一個Wangle handler可以同時掌控上游和下游的兩個方向的數(shù)據(jù)流動。當你把所有的handler連接在一起,就可以用一種靈活的方式將原始數(shù)據(jù)組裝為想要的數(shù)據(jù)類型或者將已有的數(shù)據(jù)拆分。

在我們的服務器的pipeline中大致將會有下面幾種handler:

1.Handler 1 (下文的上游下游是指對一同個handler而言,根據(jù)其在pipeline中的位置不同,輸入輸出相反) 上游:將從socket中接收的二進制數(shù)據(jù)流寫入一個零拷貝(zero-copy,指省略了Applicaion context和Kernel context之間的上下文切換,避免了CPU對Buffer的冗余拷貝,直接在Kernel級別進行數(shù)據(jù)傳輸?shù)募夹g,詳情請參閱維基百科)的字節(jié)緩存中,發(fā)送給handler2

下游:接收一個零拷貝的字節(jié)緩存,將其內容寫入socket中

2.Handler2 上游:接收handler1的緩存對象,解碼為一個string對象傳遞給handler3 下游:接收handler3的string對象,將其轉碼為一個零拷貝的字節(jié)緩存,發(fā)送給handler1

3.Handler3 上游:接收handler2中的string對象,再向下發(fā)送至pipeline等待寫回客戶端。string會發(fā)回handler2 下游:接收上游的string對象,傳遞給handler2

需要注意的一點是,每一個handler應當只做一件事并且只有一件,如果你有一個handler里做了多項任務,比如從二進制流離直接解碼出string,那么你需要學會將它拆分。這對提升代碼的可維護性和擴展性非常重要。

另外,沒錯,handler不是線程安全的,所以不要輕易的在其中使用任何沒有經(jīng)過mutex,atomic lock保護的數(shù)據(jù),如果你確實需要一個線程安全的環(huán)境,F(xiàn)olly提供了一種免于加鎖的數(shù)據(jù)結構, Folly依賴于Wangle,你可以很容易的在項目中引入并使用它。

如果你還不是很明白所有的步驟,不用著急,在看到下面的具體實現(xiàn)時你會更加清楚。

Echo Server

下面我會展示服務器的具體實現(xiàn)。我假定您已經(jīng)安裝好Wangle。需要注意的是截至目前Wangle還不能在Mac OS上安裝,我建議您可以安裝虛擬機,使用Ubuntu來安裝Wangle。

這就是echo handler:接收一個string,打印到stdout中,再發(fā)送回pipeline。要注意write語句中的定界符不可以省略,因為pipeline會按照字節(jié)解碼。

// the main logic of our echo server; receives a string and writes it straight

// back

class EchoHandler : public HandlerAdapter {

public:

 virtual void read(Context* ctx, std::string msg) override {

 std::cout << "handling " << msg << std::endl;

 write(ctx, msg + "rn");

 }

};

Echohandler其實是我們pipeline的最后一個handler,現(xiàn)在我們需要創(chuàng)建一個PipelineFactory來控制所有的request和response。

// where we define the chain of handlers for each messeage received

class EchoPipelineFactory : public PipelineFactory {

public:

 EchoPipeline::Ptr newPipeline(std::shared_ptr sock) {

 auto pipeline = EchoPipeline::create();

 pipeline->addBack(AsyncSocketHandler(sock));

 pipeline->addBack(LineBasedFrameDecoder(8192));

 pipeline->addBack(StringCodec());

 pipeline->addBack(EchoHandler());

 pipeline->finalize();

 return pipeline;

 }

};

pipeline中每一個handler的插入順序都需要嚴格注意,因為它們是按照先后排序的,此處我們有4個handler

1.AsyncSocketHandler: 上游:讀取scoket中的二進制流轉換成零拷貝字節(jié)緩存 下游:將字節(jié)緩存內容寫入底層socket

2. LineBasedFrameDecoder: 上游:接收字節(jié)緩存,按行分割數(shù)據(jù) 下游:將字節(jié)緩存發(fā)送給AsyncSocketHandler

3. StringCodec: 上游:接收字節(jié)緩存,解碼為std:string傳遞給EchoHandler 下游:接收std:string, 編碼為字節(jié)緩存,傳遞給LineBasedFrameDecoder

4. EchoHandler: 上游:接收std:string對象,將其寫入pipeline-將消息返回給Echohandler。 下游:接收一個std:string對象,轉發(fā)給StringCodec Handler。 現(xiàn)在我們所需要做的就是將pipeline factory關聯(lián)到ServerBootstrap,綁定一個端口,這樣我們已經(jīng)完成了 基本上所有的工作。

#include <gflags/gflags.h>



#include <wangle/bootstrap/ServerBootstrap.h>

#include <wangle/channel/AsyncSocketHandler.h>

#include <wangle/codec/LineBasedFrameDecoder.h>

#include <wangle/codec/StringCodec.h>



using namespace folly;

using namespace wangle;



DEFINE_int32(port, 8080, "echo server port");



typedef Pipeline<IOBufQueue&, std::string> EchoPipeline;



// the main logic of our echo server; receives a string and writes it straight

// back

class EchoHandler : public HandlerAdapter<std::string> {

public:

 virtual void read(Context* ctx, std::string msg) override {

 std::cout << "handling " << msg << std::endl;

 write(ctx, msg + "\r\n");

 }

};



// where we define the chain of handlers for each messeage received

class EchoPipelineFactory : public PipelineFactory<EchoPipeline> {

public:

 EchoPipeline::Ptr newPipeline(std::shared_ptr<AsyncTransportWrapper> sock) {

 auto pipeline = EchoPipeline::create();

 pipeline->addBack(AsyncSocketHandler(sock));

 pipeline->addBack(LineBasedFrameDecoder(8192));

 pipeline->addBack(StringCodec());

 pipeline->addBack(EchoHandler());

 pipeline->finalize();

 return pipeline;

 }

};



int main(int argc, char** argv) {

 google::ParseCommandLineFlags(&argc, &argv, true);



 ServerBootstrap<EchoPipeline> server;

 server.childPipeline(std::make_shared<EchoPipelineFactory>());

 server.bind(FLAGS_port);

 server.waitForStop();



 return 0;

}

至此我們一共只寫了48行代碼就完成了一個高性能的異步C++服務器。

Echo Client

echo客戶端的實現(xiàn)與我們的服務端非常類似:

// the handler for receiving messages back from the server

class EchoHandler : public HandlerAdapter {

public:

 virtual void read(Context* ctx, std::string msg) override {

 std::cout << "received back: " << msg;

 }

 virtual void readException(Context* ctx, exception_wrapper e) override {

 std::cout << exceptionStr(e) << std::endl;

 close(ctx);

 }

 virtual void readEOF(Context* ctx) override {

 std::cout << "EOF received :(" << std::endl;

 close(ctx);

 }

};

注意我們重載了readException和readEOF兩個方法,還有其他一些方法可以被重載。如果你需要控制某個特別的事件,只需要重載對應的虛函數(shù)即可。

這是客戶端的pipeline factory的實現(xiàn),與我們的服務端結構基本一致,只有EventBaseHandler這個handler在服務端代碼中不曾出現(xiàn),它可以確保我們可以從任意一個線程寫入數(shù)據(jù)。

// the handler for receiving messages back from the server

class EchoHandler : public HandlerAdapter {

public:

 virtual void read(Context* ctx, std::string msg) override {

 std::cout << "received back: " << msg;

 }

 virtual void readException(Context* ctx, exception_wrapper e) override {

 std::cout << exceptionStr(e) << std::endl;

 close(ctx);

 }

 virtual void readEOF(Context* ctx) override {

 std::cout << "EOF received :(" << std::endl;

 close(ctx);

 }

};

客戶端所有的代碼如下圖所示

#include <gflags/gflags.h>

#include



#include <wangle/bootstrap/ClientBootstrap.h>

#include <wangle/channel/AsyncSocketHandler.h>

#include <wangle/channel/EventBaseHandler.h>

#include <wangle/codec/LineBasedFrameDecoder.h>

#include <wangle/codec/StringCodec.h>



using namespace folly;

using namespace wangle;



DEFINE_int32(port, 8080, "echo server port");

DEFINE_string(host, "::1", "echo server address");



typedef Pipeline<folly::IOBufQueue&amp;, std::string> EchoPipeline;



// the handler for receiving messages back from the server

class EchoHandler : public HandlerAdapter {

public:

 virtual void read(Context* ctx, std::string msg) override {

 std::cout << "received back: " << msg;

 }

 virtual void readException(Context* ctx, exception_wrapper e) override {

 std::cout << exceptionStr(e) << std::endl;

 close(ctx);

 }

 virtual void readEOF(Context* ctx) override {

 std::cout << "EOF received :(" << std::endl;

 close(ctx);

 }

};



// chains the handlers together to define the response pipeline

class EchoPipelineFactory : public PipelineFactory {

public:

 EchoPipeline::Ptr newPipeline(std::shared_ptr sock) {

 auto pipeline = EchoPipeline::create();

 pipeline->addBack(AsyncSocketHandler(sock));

 pipeline->addBack(

 EventBaseHandler()); // ensure we can write from any thread

 pipeline->addBack(LineBasedFrameDecoder(8192, false));

 pipeline->addBack(StringCodec());

 pipeline->addBack(EchoHandler());

 pipeline->finalize();

 return pipeline;

 }

};



int main(int argc, char** argv) {

 google::ParseCommandLineFlags(&amp;argc, &amp;argv, true);



 ClientBootstrap client;

 client.group(std::make_shared(1));

 client.pipelineFactory(std::make_shared());

 auto pipeline = client.connect(SocketAddress(FLAGS_host, FLAGS_port)).get();



 try {

 while (true) {

 std::string line;

 std::getline(std::cin, line);

 if (line == "") {

 break;

 }



 pipeline->write(line + "rn").get();

 if (line == "bye") {

 pipeline->close();

 break;

 }

 }

 } catch (const std::exception&amp; e) {

 std::cout << exceptionStr(e) << std::endl;

 }



 return 0;

}

程序用一個While循環(huán)不斷監(jiān)測用戶的輸入,并且依靠調用.get() 來同步等待一直到請求被響應。

以上就是C++編寫高性能服務器實例教程的詳細內容,更多關于C++高性能服務器的資料請關注腳本之家其它相關文章!

相關文章

  • OpenCV實現(xiàn)無縫克隆算法的步驟詳解

    OpenCV實現(xiàn)無縫克隆算法的步驟詳解

    借助無縫克隆算法,您可以從一張圖像中復制一個對象,然后將其粘貼到另一張圖像中,從而形成一個看起來無縫且自然的構圖。本文將詳解OpenCV實現(xiàn)無縫克隆算法的步驟,需要的可以參考一下
    2022-06-06
  • C++實現(xiàn)掃雷游戲(控制臺版)

    C++實現(xiàn)掃雷游戲(控制臺版)

    這篇文章主要為大家詳細介紹了C++實現(xiàn)掃雷游戲,控制臺版的掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • C語言鏈表實現(xiàn)銷售管理系統(tǒng)

    C語言鏈表實現(xiàn)銷售管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言鏈表實現(xiàn)銷售管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 代碼分析c++中string類

    代碼分析c++中string類

    本篇內容通過詳細的源代碼詳細分析了C++中string類的用法以及知識點,有興趣的讀者們參考下。
    2018-03-03
  • VS Code 中搭建 Qt 開發(fā)環(huán)境方案分享

    VS Code 中搭建 Qt 開發(fā)環(huán)境方案分享

    這篇文章主要介紹了VS Code 中搭建 Qt 開發(fā)環(huán)境方案分享的相關資料,需要的朋友可以參考下
    2022-12-12
  • QT5實現(xiàn)TTS文本語音朗讀功能

    QT5實現(xiàn)TTS文本語音朗讀功能

    TTS?語音朗讀?是開發(fā)中常用的功能,Qt已經(jīng)給封裝完成,我們只需要調用即可,本文就為大家介紹了QT5如何調用實現(xiàn)文本朗讀功能的,需要的可以參考一下
    2023-05-05
  • c++多線程為何要使用條件變量詳解

    c++多線程為何要使用條件變量詳解

    多線程是多任務處理的一種特殊形式,下面這篇文章主要給大家介紹了關于c++多線程為何要使用條件變量的相關資料,需要的朋友可以參考下
    2021-06-06
  • C語言 深入探究動態(tài)規(guī)劃之區(qū)間DP

    C語言 深入探究動態(tài)規(guī)劃之區(qū)間DP

    這幾天在做有關dp的題,看到一個石子合并的問題,本來以為是個貪心,后來仔細一想壓根不是貪心。貪心算法的思路是每次都取最大的,然而石子合并問題有個限制條件就是每次只能取相鄰的,這就決定了它不是個貪心
    2022-04-04
  • 快速解決boost庫鏈接出錯的問題(分享)

    快速解決boost庫鏈接出錯的問題(分享)

    下面小編就為大家?guī)硪黄焖俳鉀Qboost庫鏈接出錯的問題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 黑客帝國數(shù)字雨效果VC6源代碼分享

    黑客帝國數(shù)字雨效果VC6源代碼分享

    這篇文章主要介紹了黑客帝國數(shù)字雨效果VC6源代碼分享,本文直接給出實現(xiàn)代碼,Win7下編譯通過,效果很酷,需要的朋友可以參考下
    2015-02-02

最新評論