(十)nodejs循序漸進-高性能游戲服務器框架pomelo之介紹和安裝篇

目錄

Pomelo

安裝Pomelo

創建demoserver項目

pomelo命令

項目結構說明

pomelo框架

架構

服務器實現

客戶端請求與響應、廣播的抽象介紹


Pomelo

pomelo是一個快速、可擴展、Node.js分布式游戲服務器框架,對游戲服務器開發感興趣的同學可以關注關注。

之前做頁游,端游和手游一直都是用的C++,或者C++ + lua,C++ + golang的方式來開發,說實話,C++用起來得心用手,有多少坑自己心里有點逼數,用的大都是騰訊系的框架庫,要么是盛大系的框架庫,底層比較穩定,即使如此,但一旦有個項目要立項,之前代碼不可換皮的情況下,你發現用C++開發還真的是笨重,因為你可能又得重新編一大堆的庫,或許編完就得大半天功夫,有些工具類庫可能還得自己去寫。

后來在2018年接手國外的一個游戲項目,老外借助gameSparks平臺開發,用的nodejs,這個時候我才關注nodejs,到現在已經2年了我不算是nodejs的開發老人,但也算是用nodejs開發了不少游戲項目,那么這里我給大家分享一個比較熱門,活躍的服務器框架pomelo。

用它的主要好處:

1.?入門簡單,有比較豐富的文檔和示例(雖然現在看版本也比較老了,但是入門沒什么問題)

2.分布式多進程且擴展簡單(單進程多線程,每個服務器都是一個Node進程,通過配置文件就可以管理集群)

3.可以不去關注底層和網絡相關邏輯,聚焦業務邏輯的處理,對于有Web服務器開發經驗卻沒有游戲服務器開發經驗來說還是比較友好的

4.提供了很多工具和客戶端支持(像IOS、Android & Java、Javascript、C、Cocos2d-x、U3D等)

?

安裝Pomelo

安裝要求 

 不管是windows還是linux 我更喜歡用源碼安裝,畢竟源碼時最新的,而且我也可以選擇版本來更新。

比如用命令簡單傻瓜操作:

npm install pomelo -g

如果用源碼安裝:

git clone https://github.com/NetEase/pomelo.git
cd pomelo
npm install -g

安裝完之后看到我的版本信息:

說明:Pomelo安裝可能出現各種失敗

    1.?回頭去檢查一下,Python是否2.5 < version < 3.0和VC++編輯器是否有問題

    2.如果以前全局安裝過Pomelo,最好刪除掉 “C:\Users\當前用戶\AppData\Roaming\npm\node_modules”目錄下Pomelo文件夾和“C:\Users\當前用戶\AppData\Roaming\npm-cache”目錄下Pomelo開頭的文件夾

    3.如果并不報錯,npm卡住不動,多數是網絡原因,重復多安幾次;或者打開FQ工具試試;也可以用淘寶鏡像?cnpm?安裝.

創建demoserver項目

$ pomelo init ./demoserver

或者使用命令

$ mkdir demoserver
$ cd demoserver
$ pomelo init

在初始化項目過程中需要你選擇網絡連接協議:

Please select underly connector, 1 for websocket(native socket), 2 for socket.io, 3 for wss, 4 for socket.io(wss), 5 for udp, 6 for mqtt

除了5 for udp,其它都是長連接,我們接下來選擇1,至于這些協議之間有什么區別,請各位自行查找資料,這里不贅述了。

如果你不小心選擇網絡協議錯了,不要緊,你仍然有機會修改app.js的配置 :

如果你需要替換成wss,那么你只需要參考app.js.wss里的配置,修改里邊對應的位置:

項目初始化成功后轉到項目根目錄,執行安裝項目執行 npm-install.bat 依賴項 (其它平臺執行npm-install.sh),接下來我有必要說一下pomelo的命令,因為你在目前或者后期會經常和一些命令打交道。

pomelo命令

命令行工具pomelo是Pomelo框架提供的一個小工具,該工具能夠幫助開發者更便捷、更有效率地進行應用開發。該工具包括的命令支持絕大多數的應用開發操作,包括創建初始項目、啟動應用、停止應用、關閉應用等。

init
init: 創建一個新項目,該項目中包含創建pomelo應用的基本文件及pomelo應用的簡單示例。支持相對路徑和絕對路徑。默認情況下為當前路徑,項目名稱為當前文件夾名稱。

pomelo init? projectname

在創建新項目時,需要選擇新項目使用的與客戶端通信時使用的connector,1代表Websocket(native socket),2代表?socket.io。

start
start: 啟動應用及服務器。

pomelo start [-e,–env ] [-d,–directory?] [-D,–daemon] 命令格式

其中,-e 用來選擇啟動時使用的env,如production,development,stress-test等; -d 用來指定項目目錄; -D 用來開啟daemon模式啟動,如果開啟了daemon,那么進程將轉入后臺運行, 所有的日志將不再打印到console上,只能通過對應的日志文件查看日志。

list

list: 列出當前應用開啟的所有服務器的信息,包括服務器Id、服務器類型、pid、堆使用情況、啟動時長。

pomelo list [-u,–username ] [-p,–password ] [-h,–host ] [-P,–port ] 命令格式

當應用啟動后,該命令列出所有服務器信息。由于當執行此操作時,pomelo是作為監控管理框架的一個客戶端的,在連接注冊到master上的時候,需要進行身份驗證。默認生成的項目中,有一個默認的用戶名admin,口令也為admin,因此在不指定用戶名和口令的時候,默認使用的用戶名和口令均為admin,下面的stop命令和kill命令均需要使用用戶名和口令驗證,默認值與此處相同。應用的管理用戶可以通過修改config/adminUser.json文件進行配置;
執行本命令時,還需要指定master服務器的ip和port, 這樣可以是的pomelo list可以在任意地方執行。pomelo stop/kill/add等也同樣需要指定master服務器的ip和port,默認使用127.0.0.1:3005作為master服務器的地址。

4 . pomelo命令:stop

stop: 關閉應用及服務器或者停止指定的服務器。

pomelo stop [-u,–username ] [-p,–password ] [-h,–host ] [-P,–port ] […] 命令格式

stop用來停止當前應用,優雅地關閉應用。和kill命令不同,這種關閉首先會切斷客戶端與服務器的連接,然后逐一關閉所有服務器。如果指定了服務器serverId的話,則會關閉特定的服務器,而不是關閉所有的服務器。與list命令一樣,需要權限驗證,默認的用戶名和密碼均為admin,也需要指定master服務器的位置, 跟pomelo list一樣,默認使用127.0.0.1:3005。

kill
該命令需在項目的根目錄或game-server下使用;
kill: 強制關閉應用及服務器。

pomelo kill [-u,–username ] [-p,–password ] [-h,–host ] [-P,–port ] [-f,–force]

該命令強制關閉應用。在本地進行應用開發過程中,如果遇到kill之后還有服務器進程沒有關閉的情況,可以增加–force選項,強制關閉所有服務器進程。該操作相當地暴力,可能產生數據丟失等不好的影響,可以在開發調試時使用,不推薦在線上使用該命令。該命令同樣也需要進行身份驗證以及指定master服務器的位置,具體方式同list和stop。

6 . pomelo命令:add

add: 運行時動態添加服務器。pomelo add也需要身份驗證以及指定master服務器的地址。

pomelo add [-u,–username ] [-p,–password ] [-h,–host ] [-P,–port ] […]

args參數是用來指定新增服務器的參數的,包括服務器類型,服務器id等, 支持一次增加一臺或多臺同類型的服務器;示例如下:

pomelo add host=127.0.0.1 port=8000++ clientPort=9000++ frontend=true clusterCount=3 serverType=connector
pomelo add host=127.0.0.1 port=8000 clientPort=9000 frontend=true serverType=connector id=added-connector-server

masterha

masterha: 當啟用masterha高可用的時候,用來啟動master服務器的slave節點。需要在game-server/config目錄下配置masterha.json。其他的命令行參數類似于pomelo start;

pomelo masterha [-d,–direcotry?]

其他命令
–version:列出當前使用pomelo的版本信息。
–help:列出所有pomelo支持的命令及使用說明。

項目結構說明

  game-server :??游戲服務器,所有游戲服務器功能和邏輯都在此目錄下

    game-server/app.js:入口文件

    game-server/app:?存放游戲邏輯和功能相關代碼都這個子目錄下,servers目錄下可以新建多個目錄來創建不同類型的服務器,在pomelo中,使用路徑來區分服務器類型

    game-server/config:存放游戲服務器配置文件目錄,像日志、服務器、數據庫等幾乎所有配置文件都可以存放到此目錄下

    game-server/logs:日志目錄,存放游戲服務器所有日志文件

  web-server:? web服務器(如果你是個H5游戲,這里就是Web客戶端,如果是IOS、Andriod客戶端,這目錄就沒什么用)

  shared:公共代碼存放處,這里要以放一些共用代碼

?所有依賴項安裝成功后,開始啟動項目

???啟動game-server

cd game-server
pomelo start

?

測試連接

? 1.啟動web-server

cd web-server
node app

修改web-server里的app.js :

打開瀏覽器:

測試gameserver

這里可以用我剛才說的pomelo命令查看下當前的服務器:

?

好了,你現在可以運行demo了,那么接下來就得開始循序漸進熟悉框架了

pomelo框架

架構

該架構把游戲服務器做了抽象, 抽象成為兩類:前端服務器和后端服務器, 如圖:

該架構把游戲服務器做了抽象, 抽象成為兩類:前端服務器和后端服務器

前端服務器(frontend)的職責:

>負責承載客戶端請求的連接

>維護session信息

>把請求轉發到后端

>把后端需要廣播的消息發到前端

后端服務器(backend)的職責:

>處理業務邏輯, 包括RPC和前端請求的邏輯

>把消息推送回前端

服務器實現

動態語言的面向對象有個基本概念叫鴨子類型 服務器的抽象也同樣可以比喻為鴨子, 服務器的對外接口只有兩類, 一類是接收客戶端的請求, 叫做handler, 一類是接收RPC請求, 叫做remote, handler和remote的行為決定了服務器長什么樣子。 因此我們只要定義好handler和remote兩類的行為, 就可以確定這個服務器的類型。

服務器抽象的實現

利用目錄結構與服務器對應的形式, 可以快速實現服務器的抽象。

以下是示例圖:

利用目錄結構與服務器對應的形式, 可以快速實現服務器的抽象。

圖中的connector, connector, gate三個目錄代表三類服務器類型, 每個目錄下的handler與remote決定了這個服務器的行為(對外接口)。 開發者只要往handler與remote目錄填代碼, 就可以實現某一類的服務器。這讓服務器實現起來非常方便。 讓服務器動起來, 只要填一份配置文件servers.json就可以讓服務器快速動起來。 配置文件和對應的進行架構如下所示:

1 . gate服務器
一個應用的gate服務器,一般不參與rpc調用,也就是說其配置項里可以沒有port字段,僅僅有clientPort字段,它的作用是做前端的負載均衡。客戶端往往首先向gate服務器發出請求,gate會給客戶端分配具體的connector服務器。具體的分配策略一般是根據客戶端的某一個key做hash得到connector的id,這樣就可以實現各個connector服務器的負載均衡。

2 . connector服務器
connector服務器接收客戶端的連接請求,創建與客戶端的連接,維護客戶端的session信息。同時,接收客戶端對后端服務器的請求,按照用戶配置的路由策略,將請求路由給具體的后端服務器。當后端服務器處理完請求或者需要給客戶端推送消息的時候,connector服務器同樣會扮演一個中間角色,完成對客戶端的消息發送。connector服務器會同時擁有clientPort和port,其中clientPort用來監聽客戶端的連接,port端口用來給后端提供服務。

目前pomelo提供了hybridconnector和sioconnector,其中hybridconnector支持tcp,websocket; sioconnector支持socket.io。但是實際編程中,只有這些connector可能還無法滿足我們的需求,我們可能需要自己定制自己的connector,pomelo提供了定制connector的接口,我們將會在后邊的項目實例種用到。

3 . 應用邏輯服務器
gate服務器和connector服務器又都被稱作前端服務器,應用邏輯服務器是后端服務器,它完成實際的應用邏輯,提供服務給客戶端,當然客戶端的請求是通過前端服務器路由過來的。后端服務器之間也會通過rpc調用而有相互之間的交互。由于后端服務器不會跟客戶端直接有連接,因此后端服務器只需監聽它提供服務的端口即可。

4 . master服務器
master服務器加載配置文件,通過讀取配置文件,啟動所配置的服務器集群,并對所有服務器進行管理。

5 . rpc調用
pomelo中使用rpc調用進行進程間通信,在pomelo中rpc調用分為兩大類,使用namespace進行區分,namespace為sys的為系統rpc調用,它對用戶來說是透明的,目前pomelo中系統rpc調用有:
1.后端服務器向前端服務器請求session信息
2.后端服務器通過channel推送消息時對前端服務器發起的rpc調用
3.前端服務器將用戶請求路由給后端服務器時也是sys rpc調用
除了系統rpc調用外,其余的由用戶自定義的rpc調用屬于user namespace的rpc調用,需要用戶自己完成rpc服務端remote的handle代碼,并由rpc客戶端顯式地發起調用

6 . route,touter
route用來標識一個具體服務或者客戶端接受服務端推送消息的位置,對服務端來說,其形式一般是…,例如"chat.chatHandler.send", chat就是服務器類型,chatHandler是chat服務器中定義的一個Handler,send則為這個Handler中的一個handle方法。對客戶端來說,其路由一般形式為onXXX,當服務端推送消息時,客戶端會有相應的回調。 一般來說具體的同類型應用服務器都會有多個,當客戶端請求到達后,前端服務器會將用戶客戶端請求派發到后端服務器,這種派發需要一個路由函數router,可以粗略地認為router就是根據用戶的session以及其請求內容,做一些運算后,將其映射到一個具體的應用服務器id。可以通過application的route調用給某一類型的服務器配置其router。如果不配置的話,pomelo框架會使用一個默認的router。pomelo默認的路由函數是使用session里面的uid字段,計算uid字段的crc32校驗碼,然后用這個校驗碼作為key,跟同類應用服務器數目取余,得到要路由到的服務器編號。注意這里有一個陷阱,就是如果session沒有綁定uid的話,此時uid字段為undefined,可能會造成所有的請求都路由到同一臺服務器。所以在實際開發中還是需要自己來配置router。

7 . Channel
channel可以看作是一個玩家id的容器,主要用于需要廣播推送消息的場景。可以把某個玩家加入到一個Channel中,當對這個Channel推送消息的時候,所有加入到這個Channel的玩家都會收到推送過來的消息。一個玩家的id可能會被加入到多個Channel中,這樣玩家就會收到其加入的Channel推送過來的消息。需要注意的是Channel都是服務器本地的,應用服務器A和B并不會共享Channel,也就是說在服務器A上創建的Channel,只能由服務器A才能給它推送消息。

8 . request, response, notify, push
pomelo中有四種消息類型的消息,分別是request,response,notify和push,客戶端發起request到服務器端,服務器端處理后會給其返回響應response;notify是客戶端發給服務端的通知,也就是不需要服務端給予回復的請求;push是服務端主動給客戶端推送消息的類型。

9 . filter
filter分為before和after兩類,每類filter都可以注冊多個,形成一個filter鏈,所有的客戶端請求都會經過filter鏈進行一些處理。before filter會對請求做一些前置處理,如:檢查當前玩家是否已登錄,打印統計日志等。after filter是進行請求后置處理的地方,如:釋放請求上下文的資源,記錄請求總耗時等。after filter中不應該再出現修改響應內容的代碼,因為在進入after filter前響應就已經被發送給客戶端。

10 . handler
handler是實現具體業務邏輯的地方,在請求處理流程中,它位于before filter和after filter之間,handler的接口聲明如下:

handler.methodName = function(msg, session, next) {
// …
}

參數含義與before filter類似。handler處理完畢后,如有需要返回給客戶端的響應,可以將返回結果封裝成js對象,通過next傳遞給后面流程。

11 . error handler
error handler是一個處理全局異常的地方,可以在error handler中對處理流程中發生的異常進行集中處理,如:統計錯誤信息,組織異常響應結果等。error handler函數是可選的,格式如下:

app.set(‘errorHandler’, handleFunc);
來向pomelo框架進行注冊,函數聲明如下:
errorHandler = function(err, msg, resp, session, next) {
// …
}
err是前面流程中發生的異常;resp是前面流程傳遞過來,需要返回給客戶端的響應信息。

12 . component
pomelo 框架是由一些松散耦合的component組成的,每個component完成一些功能。每個component往往有start,afterStart,stop等調用,用來完成生命周期管理。

13 . admin client, monitor, master
monitor運行在各個應用服務器中,它會向master注冊自己,向master上報其服務器的信息,當服務器群有變化時,接收master推送來的變化消息,更新其服務器上下文。
master運行在應用服務器中,它會收集整個服務器群的信息,有變化時會將變化推送到各個monitor;同時,master還接受admin client的請求,按照client發出的命令,執行對應的操作。
client獨立運行自己的進程,它會發起到master的連接,然后通過對master發出請求或者命令,來管理整個服務器群。

14 . admin module
在pomelo中,module特指服務器監控管理模塊,實現的是監控邏輯,比如收集進程狀態等。用戶在使用時,可以通過application的registerAdmin注冊管理模塊,實現自己定制的監控管理功能。每一個module中都會定義可選的四種回調函數:

  1. masterHandler(agent, msg, cb) 當有應用服務器給master發監控數據時,這個回調函數會由master進程進行回調,完成應用服務器的消息處理;
  2. monitorHandler(agent, msg, cb) 當有master請求應用服務器的一些監控信息時,由應用服務器進行回調,完成對master請求的處理;
  3. clientHandler(agent, msg, cb)當由管理客戶端向master請求服務器群信息時,由master進程進行回調處理客戶端的請求。
  4. start(cb) 當admin module,注冊加載完成后,這個回調會被執行,在這里可以做一些初始化工作。

客戶端請求與響應、廣播的抽象介紹

所有的web應用框架都實現了請求與響應的抽象。盡管游戲應用是基于長連接的, 但請求與響應的抽象跟web應用很類似。 下圖的代碼是一個request請求示例:

深入淺出node.js游戲服務器開發——Pomelo框架的設計動機與架構介紹

請求的api與web應用的ajax請求很象,基于Convention over configuration的原則, 請求不需要任何配置。 如下圖所示,請求的route字符串:chat.chatHandler.send, 它可以將請求分發到chat服務器上chatHandler文件定義的send方法。

Pomelo的框架里還實現了request的filter機制,廣播/組播機制,詳細介紹見pomelo框架參考。

服務器間RPC調用的抽象介紹

架構中各服務器之間的通訊主要是通過底層RPC框架來完成的,該RPC框架主要解決了進程間消息的路由和RPC底層通訊協議的選擇兩個問題。 服務器間的RPC調用也實現了零配置。實例如下圖所示:

深入淺出node.js游戲服務器開發——Pomelo框架的設計動機與架構介紹

上圖的remote目錄里定義了一個RPC接口: chatRemote.js,它的接口定義如下:

chatRemote.kick = function(uid, player, cb) {}

其它服務器(RPC客戶端)只要通過以下接口就可以實現RPC調用:

app.rpc.chat.chatRemote.kick(session, uid, player, function(data){});

?這個調用會根據特定的路由規則轉發到特定的服務器。(如場景服務的請求會根據玩家在哪個場景直接轉發到對應的server)。

rpc的使用遠比其它rpc框架簡單好多,因為我們無需寫任何配置文件,也無需生成stub。因為我們服務器抽象的實現的方式,使得rpc客戶端可以在應用啟動時掃描服務器目錄自動生成stub對象。

完成了以上三個目標, 一個實時的分布式應用框架的輪廓就搭出來了。接下來我們在下一章節里說明下在當前demoserver的基礎上不斷地擴充,豐富它的功能。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444539.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444539.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444539.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leetcode344. 反轉字符串 史上最簡單力扣題

編寫一個函數&#xff0c;其作用是將輸入的字符串反轉過來。輸入字符串以字符數組 char[] 的形式給出。 不要給另外的數組分配額外的空間&#xff0c;你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。 你可以假設數組中的所有字符都是 ASCII 碼表中的可打印字符。…

(十一)nodejs循序漸進-高性能游戲服務器框架pomelo之啟動流程和組件

游戲啟動過程 啟動入口 在使用pomelo進行游戲開發時&#xff0c;工程目錄下的app.js是整個游戲服務器的啟動運行入口。app.js中創建項目&#xff0c;進行默認配置并啟動服務器的代碼如下&#xff1a; var pomelo require(pomelo); var app pomelo.createApp(); app.set(na…

(十二)nodejs循序漸進-高性能游戲服務器框架pomelo之創建一個游戲聊天服務器

上個章節我們簡單介紹了下pomelo的安裝和目錄結構&#xff0c;有讀者可能覺得有點吃不消&#xff0c;為什么不再深入講一講目錄結構和里邊的庫&#xff0c;這里我就不費口舌了&#xff0c;大家可以去官網參考文檔說明&#xff0c;本文只告訴大家如何利用這個框架來開發自己的東…

看這玩意復習你還會掛科?《軟件工程篇》

軟件工程&#xff1a;是指導軟件開發和維護的一門工程學科 三要素方法/工具/開發過程 價值&#xff1a;促進項目成功 現代產品開發三原則&#xff1a;功用性、可行性、稱許性 軟件過程是軟件工程的核心組成部分。 迭代 &#xff1a;反復求精 增量&#xff1a;逐塊建造 需…

C++:02---命名空間

一、概念: ①類似于倉庫,空間內存儲代碼,需要用到時調用②也為防止名字沖突提供了更加可控的機制二、命名空間的定義 定義的基本格式如下:namespace 命名空間名 { //一系列聲明與定義 };三、命名空間的注意事項 命名空間定義時最后的分號可有可無只要出現在全局作用域中的…

看這玩意復習你還會掛科?《軟件工程2篇》

第一章&#xff1a; 軟件工程定義&#xff1a; 1968年10月&#xff0c;Fritz Bauer 首次提出了“軟件工程”的概念&#xff0c;并將“軟件工程”定義為&#xff1a;為了經濟地獲得能夠在實際機器上有效運行的可靠軟件&#xff0c;而建立并使用的一系列工程化原則。 1993年IE…

C++:05---命名空間

一、概念: ①類似于倉庫,空間內存儲代碼,需要用到時調用②也為防止名字沖突提供了更加可控的機制二、命名空間的定義 定義的基本格式如下:namespace 命名空間名 { //一系列聲明與定義 };三、命名空間的注意事項 命名空間定義時最后的分號可有可無只要出現在全局作用域中的…

C++:04---內聯函數

1.概念: 內聯類似于宏定義,當程序執行到內聯函數時,相當于復制了一份函數代碼。犧牲代碼空間,贏得了時間 內聯說明只是向編譯器發出一個請求,編譯器可以選擇忽略這個請求 2.關鍵字:inline 聲明時寫了inline,定義時可省略。建議聲明和定義都加上inlineinline int add(int…

leetcode86. 分隔鏈表

給定一個鏈表和一個特定值 x&#xff0c;對鏈表進行分隔&#xff0c;使得所有小于 x 的節點都在大于或等于 x 的節點之前。 你應當保留兩個分區中每個節點的初始相對位置。 示例: 輸入: head 1->4->3->2->5->2, x 3 輸出: 1->2->2->4->3->5…

(十三)nodejs循序漸進-高性能游戲服務器框架pomelo之擴展聊天服務器為機器人自動聊天

聊天服務器擴展 大家在上一篇文章里相信已經學會了pomelo框架的基本用法了&#xff0c;那么我們在上一篇文章的代碼基礎上繼續擴展&#xff0c;豐富系統&#xff0c;另外也熟悉下他的更多的用法&#xff0c;這一節我將擴展它&#xff1a;增加一個機器人自動聊天的功能。 目的…

C++:09---類靜態成員、類常量成員

一、類靜態成員(static) 先介紹一下什么是靜態變量、靜態函數 靜態局部變量:存在域(全局數據區),作用域(塊作用域)靜態全局變量:存在域(全局數據區),作用域(整個文件)靜態函數:存在域(全局數據區),作用域(整個文件)static int a=10;//全局靜態變量 static vo…

C++:08---成員變量初始化方式

成員變量初始化有三種方式: 在構造函數體內賦值初始化在自定義的公有函數體中賦值初始化(一般用于成員變量的初始化)在構造函數的成員初始化列表初始化一、構造函數體內初始化 說明:在構造函數體內的初始化方式,本質是是為成員變量賦值,而不是真正意義上的初始化,這點要…

leetcode1290. 二進制鏈表轉整數 刷新認知,最簡單算法題

給你一個單鏈表的引用結點 head。鏈表中每個結點的值不是 0 就是 1。已知此鏈表是一個整數數字的二進制表示形式。 請你返回該鏈表所表示數字的 十進制值 。 示例 1&#xff1a; 輸入&#xff1a;head [1,0,1] 輸出&#xff1a;5 解釋&#xff1a;二進制數 (101) 轉化為十進…

Redis:02---安裝Redis(Linux+Windows+Docker)

Linux安裝&#xff1a;一、安裝方式1&#xff08;下載源碼編譯安裝&#xff09;第一步&#xff1a;從下面的網址中下載Redis最新穩定版本的源代碼sudo wget http://download.redis.io/redis-stable.tar.gz第二步&#xff1a;下載完之后解壓&#xff0c;建立一個軟鏈接指向于red…

C++:10---再議拷貝構造函數

一、概念 使用一個已經存在的對象,去構造(初始化)另一個對象二、格式 參數加上const&,因為拷貝構造函數在幾種情況下都會被隱式地使用,因此拷貝構造函數不應該是explict的const:防止函數內部修改值&:防止無限循環拷貝類名(類名 const& 參數名) { 函數體 }三、…

人的思維謬誤與心理學效應

啟發法 用一個容易的問題代替難以回答的真正問題。這個容易的問題的答案就是對真正問題的啟發&#xff0c;但啟發經常和真正的答案差得很遠&#xff0c;而人卻往往把啟發當成了真正問題的答案。 接下來介紹和啟發法相關的心理效應和謬誤。每一個謬誤都會注明真正的問題是什么…

C++:07---this指針

一、this指針介紹 概念:this指針是成員函數的一個隱式參數,在類中本質上就是對象的指針(常量指針)特點:在成員函數中可通過this指針區別成員變量與形參變量this可以顯式調用示例代碼:class Cperson { private: int age; float height; public: void InitPerson(int age,flo…

Redis :01---Redis簡介和安裝

一、Redis簡介 Redis官網&#xff1a;https://redis.io/ Redis是一種基于鍵值對&#xff08;key-value&#xff09;的NoSQL數據庫 與很多鍵值對數據庫不同的是&#xff0c;Redis中的值可以是由string&#xff08;字符串&#xff09;、hash&#xff08;哈希&#xff09;、 list&…

215. 數組中的第K個最大元素 BFPRT最牛解法

在未排序的數組中找到第 k 個最大的元素。請注意&#xff0c;你需要找的是數組排序后的第 k 個最大的元素&#xff0c;而不是第 k 個不同的元素。 示例 1: 輸入: [3,2,1,5,6,4] 和 k 2 輸出: 5 示例 2: 輸入: [3,2,3,1,2,4,5,5,6] 和 k 4 輸出: 4 說明: 你可以假設 k 總是…

C++: 06---構造函數析構函數

拷貝構造函數: 用一個已經存在的對象來生成一個相同類型的新對象。(淺拷貝)默認的拷貝構造函數: 如果自定義了拷貝構造函數,編譯器就不在生成默認的拷貝構造函數。 如果沒有自定義拷貝構造函數,但在代碼中用到了拷貝構造函數,編譯器會生成默認…