第1章 C++必知必會 1
1.1 C++ RAII慣用法 1
1.1.1 版本1:最初的寫法 1
1.1.2 版本2:使用goto語句 3
1.1.3 版本3:使用do...while(0)循環 5
1.1.4 版本4:使用RAII慣用法 7
1.1.5 小結 12
1.2 pimpl慣用法 12
1.3 C++ 11/14/17新增的實用特性 17
1.4 統一的類成員初始化語法與std::initializer_list 19
1.5 C++ 17注解標簽(attributes) 24
1.5.1 C++ 98/03的enumeration和C++ 11的enumerator 25
1.5.2 C++ 17的注解標簽 25
1.6 final、override關鍵字和=default、=delete語法 28
1.6.1 final關鍵字 28
1.6.2 override關鍵字 29
1.6.3 =default語法 31
1.6.4 =delete語法 32
1.7 auto關鍵字的用法 34
1.8 Range-based循環語法 35
1.8.1 自定義對象如何支持Range-based循環語法 37
1.8.2 for-each循環的實現原理 38
1.9 C++ 17結構化綁定 39
1.10 stl容器新增的實用方法 43
1.10.1 原位構造與容器的emplace係列函數 43
1.10.2 std::map的try_emplace方法與insert_or_assign方法 44
1.11 stl 中的智能指針類詳解 52
1.11.1 C++ 98/03的嘗試——std::auto_ptr 52
1.11.2 std::unique_ptr 55
1.11.3 std::shared_ptr 59
1.11.4 std::enable_shared_from_this 61
1.11.5 std::weak_ptr 63
1.11.6 智能指針對象的大小 67
1.11.7 使用智能指針時的注意事項 68
第2章 C++後端開發必備的工具和調試知識 71
2.1 SSH工具與FTP工具 71
2.1.1 Xshell 71
2.1.2 FTP 75
2.2 makefile與CMake 76
2.3 使用Visual Studio管理和閱讀開源項目代碼 83
2.4 gdb調試 87
2.4.1 被調試的程序需要帶調試信息 87
2.4.2 啓動gdb調試的方法 89
2.5 gdb常用命令詳解——利用gdb調試Redis 94
2.5.1 gdb常用調試命令概覽和說明 94
2.5.2 用gdb調試Redis前的準備工作 96
2.5.3 run命令 97
2.5.4 continue命令 98
2.5.5 break命令 98
2.5.6 tbreak命令 101
2.5.7 backtrace與frame命令 101
2.5.8 info break、enable、disable、delete命令 102
2.5.9 list命令 104
2.5.10 print與ptype命令 107
2.5.11 info與thread命令 109
2.5.12 next、step、until、finish、return、jump命令 112
2.5.13 disassemble命令 122
2.5.14 set args與show args命令 122
2.5.15 watch命令 123
2.5.16 display命令 124
2.5.17 dir命令 125
2.6 使用gdb調試多綫程程序 126
2.6.1 調試多綫程程序的方法 126
2.6.2 在調試時控製綫程切換 128
2.7 使用gdb調試多進程程序——以調試Nginx為例 137
2.8 gdb實用調試技巧 143
2.8.1 將print輸齣的字符串或字符數組完整顯示 144
2.8.2 讓被gdb調試的程序接收信號 144
2.8.3 函數明明存在,添加斷點時卻無效 145
2.8.4 調試中的斷點 146
2.8.5 自定義gdb調試命令 147
2.9 gdb tui——gdb圖形化界麵 148
2.9.1 開啓gdb TUI模式 149
2.9.2 gdb TUI模式下的4個窗口 149
2.9.3 解決tui窗口不自動更新內容的問題 150
2.9.4 窗口焦點切換 150
2.10 gdb的升級版——cgdb 151
2.11 使用VisualGDB調試 154
2.11.1 使用VisualGDB調試已經運行的程序 155
2.11.2 使用VisualGDB從頭調試程序 156
第3章 多綫程編程與資源同步 159
3.1 綫程的基本概念及常見問題 159
3.1.1 主綫程退齣,支綫程也將退齣嗎 159
3.1.2 某個綫程崩潰,會導緻進程退齣嗎 160
3.2 綫程的基本操作 160
3.2.1 創建綫程 160
3.2.2 獲取綫程ID 166
3.2.3 等待綫程結束 173
3.3 慣用法:將C++類對象實例指針作為綫程函數的參數 178
3.4 整型變量的原子操作 184
3.4.1 為什麼給整型變量賦值不是原子操作 185
3.4.2 Windows平颱上對整型變量的原子操作 186
3.4.3 C++ 11對整型變量原子操作的支持 187
3.5 Linux綫程同步對象 190
3.5.1 Linux互斥體 190
3.5.2 Linux信號量 198
3.5.3 Linux條件變量 202
3.5.4 Linux讀寫鎖 208
3.6 Windows綫程同步對象 217
3.6.1 WaitForSingleObject與WaitForMultipleObjects函數 217
3.6.2 Windows臨界區對象 219
3.6.3 Windows Event對象 224
3.6.4 Windows Mutex對象 229
3.6.5 Windows Semaphore對象 231
3.6.6 Windows讀寫鎖 235
3.6.7 Windows條件變量 238
3.6.8 在多進程之間共享綫程同步對象 243
3.7 C++ 11/14/17綫程同步對象 244
3.7.1 std::mutex係列 244
3.7.2 std::shared_mutex 248
3.7.3 std::condition_variable 253
3.8 如何確保創建的綫程一定能運行 256
3.9 多綫程使用鎖經驗總結 258
3.9.1 減少鎖的使用次數 258
3.9.2 明確鎖的範圍 259
3.9.3 減少鎖的使用粒度 259
3.9.4 避免死鎖的一些建議 260
3.9.5 避免活鎖的一些建議 262
3.10 綫程局部存儲 262
3.10.1 Windows的綫程局部存儲 262
3.10.2 Linux的綫程局部存儲 264
3.10.3 C++ 11 的 thread_local 關鍵字 267
3.11 C庫的非綫程安全函數 268
3.12 綫程池與隊列係統的設計 270
3.12.1 綫程池的設計原理 270
3.12.2 環形隊列 275
3.12.3 消息中間件 275
3.13 縴程(Fiber)與協程(Routine) 277
3.13.1 縴程 277
3.13.2 協程 280
第4章 網絡編程重難點解析 282
4.1 學習網絡編程時應該掌握的socket函數 282
4.1.1 在Linux上查看socket函數的幫助信息 283
4.1.2 在Windows上查看socket函數的幫助信息 285
4.2 TCP網絡通信的基本流程 286
4.3 設計跨平颱網絡通信庫時的一些socket函數用法 290
4.3.1 socket數據類型 290
4.3.2 在Windows上調用socket函數 290
4.3.3 關閉socket函數 291
4.3.4 獲取socket函數的錯誤碼 291
4.3.5 套接字函數的返迴值 293
4.3.6 select函數第1個參數的問題 293
4.3.7 錯誤碼WSAEWOULDBLOCK和EWOULDBLOCK 294
4.4 bind函數重難點分析 294
4.4.1 對bind函數如何選擇綁定地址 294
4.4.2 bind函數的端口號問題 295
4.5 select函數的用法和原理 302
4.5.1 Linux上的select函數 302
4.5.2 Windows上的select函數 317
4.6 socket的阻塞模式和非阻塞模式 318
4.6.1 如何將socket設置為非阻塞模式 318
4.6.2 send和recv函數在阻塞和非阻塞模式下的錶現 320
4.6.3 非阻塞模式下send和recv函數的返迴值總結 331
4.6.4 阻塞與非阻塞socket的各自適用場景 333
4.7 發送0字節數據的效果 333
4.8 connect函數在阻塞和非阻塞模式下的行為 339
4.9 連接時順便接收第1組數據 343
4.10 如何獲取當前socket對應的接收緩衝區中的可讀數據量 346
4.10.1 分析 346
4.10.2 注意事項 350
4.11 Linux EINTR錯誤碼 351
4.12 Linux SIGPIPE信號 352
4.13 Linux poll 函數的用法 353
4.14 Linux epoll模型 361
4.14.1 基本用法 361
4.14.2 epoll_wait與poll函數的區彆 363
4.14.3 LT 模式和ET 模式 363
4.14.4 EPOLLONESHOT 選項 380
4.15 高效的readv和writev函數 386
4.16 主機字節序和網絡字節序 387
4.16.1 主機字節序 387
4.16.2 網絡字節序 388
4.16.3 操作係統提供的字節轉換函數匯總 389
4.17 域名解析API介紹 390
第5章 網絡通信故障排查常用命令 397
5.1 ifconfig命令 397
5.2 ping命令 401
5.3 telnet命令 402
5.4 netstat命令 407
5.5 lsof命令 409
5.6 nc命令 412
5.7 curl命令 415
5.8 tcpdump命令 416
第6章 網絡通信協議設計 422
6.1 理解TCP 422
6.2 如何解決粘包問題 423
6.3 解包與處理 425
6.4 從struct到TLV 430
6.4.1 協議的演化 430
6.4.2 協議的分類 434
6.4.3 協議設計工具 434
6.5 整型數值的壓縮 435
6.6 設計通信協議時的注意事項 437
6.6.1 字節對齊 437
6.6.2 顯式地指定整型字段的長度 438
6.6.3 涉及浮點數時要考慮精度問題 438
6.6.4 大小端問題 438
6.6.5 協議與自動升級功能 438
6.7 包分片 439
6.8 XML與JSON格式的協議 444
6.9 一個自定義協議示例 445
6.10 理解HTTP 460
6.10.1 HTTP格式介紹 460
6.10.2 GET與POST方法 461
6.10.3 HTTP chunk編碼 465
6.10.4 HTTP客戶端的編碼實現 466
6.10.5 HTTP服務端的實現 466
6.10.6 HTTP與長連接 471
6.10.7 libcurl 471
6.10.8 Restful接口與Java Spring MVC 477
6.11 SMTP、POP3與郵件客戶端 478
6.11.1 郵件協議簡介 478
6.11.2 SMTP 479
6.11.3 POP3 494
6.11.4 郵件客戶端 499
6.12 WebSocket協議 499
6.12.1 WebSocket協議的握手過程 500
6.12.2 WebSocket協議的格式 503
6.12.3 WebSocket協議的壓縮格式 506
6.12.4 WebSocket協議裝包與解包示例 508
6.12.5 解析握手協議 512
第7章 單個服務的基本結構 515
7.1 網絡通信組件的效率問題 515
7.1.1 高效網絡通信框架的設計原則 515
7.1.2 連接的被動關閉與主動關閉 519
7.1.3 長連接和短連接 519
7.2 原始的服務器結構 520
7.3 一個連接對應一個綫程模型 522
7.4 Reactor模式 523
7.5 one thread one loop思想 524
7.5.1 one thread one loop程序的基本結構 524
7.5.2 綫程的分工 525
7.5.3 喚醒機製的實現 527
7.5.4 handle_other_things方法的實現邏輯 532
7.5.5 帶定時器的程序結構 533
7.5.6 one thread one loop的效率保障 534
7.6 收發數據的正確做法 534
7.6.1 如何收取數據 534
7.6.2 如何發送數據 535
7.6.3 不要多個綫程同時利用一個socket收(發)數據 538
7.7 發送、接收緩衝區的設計要點 538
7.7.1 為什麼需要發送緩衝區和接收緩衝區 539
7.7.2 如何設計發送緩衝區和接收緩衝區 539
7.7.3 服務端發送數據時對端一直不接收的問題 543
7.8 網絡庫的分層設計 544
7.8.1 網絡庫設計中的各個層 544
7.8.2 將Session進一步分層 550
7.8.3 連接信息與EventLoop/Thread的對應關係 551
7.9 後端服務中的定時器設計 551
7.9.1 最簡單的定時器 551
7.9.2 定時器設計的基本思路 552
7.9.3 定時器邏輯的性能優化 561
7.9.4 對時間的緩存 564
7.10 處理業務數據時是否一定要單獨開綫程 565
7.11 非侵入式結構與侵入式結構 570
7.11.1 非侵入式結構 570
7.11.2 侵入式結構 571
7.12 帶有網絡通信模塊的服務器的經典結構 578
7.12.1 為何要將listenfd設置成非阻塞模式 578
7.12.2 基於one thread one loop結構的經典服務器結構 584
7.12.3 服務器的性能瓶頸 586
第8章 Redis網絡通信模塊源碼分析 587
8.1 調試Redis環境與準備 587
8.1.1 Redis源碼編譯與啓動 587
8.1.2 通信示例與術語約定 589
8.2 探究redis-server端的網絡通信模塊 589
8.2.1 監聽fd的初始化工作 589
8.2.2 接受客戶端連接 592
8.2.3 epollfd的創建 600
8.2.4 監聽fd與客戶端fd是如何掛載到epollfd上的 601
8.2.5 readQueryFromClient函數 611
8.2.6 如何處理可寫事件 613
8.2.7 Redis 6.0多綫程網絡I/O 620
8.2.8 Redis對客戶端的管理 635
8.2.9 客戶端斷開流程 646
8.2.10 Redis中收發緩衝區的設計 653
8.2.11 定時器邏輯 659
8.2.12 鈎子函數 662
8.2.13 redis-server端網絡通信模塊小結 662
8.3 探究redis-cli端的網絡通信模型 663
8.4 Redis的通信協議格式 673
8.4.1 請求命令格式 673
8.4.2 應答命令格式 674
8.4.3 多命令和流水綫 677
8.4.4 特殊的redis-cli與內聯命令 677
8.4.5 Redis對協議數據的解析邏輯 678
第9章 服務器開發中的常用模塊設計 681
9.1 斷綫自動重連的應用場景和邏輯設計 681
9.2 保活機製與心跳包 683
9.2.1 TCP keepalive選項 683
9.2.2 應用層的心跳包機製設計 684
9.2.3 有代理的心跳包機製設計 689
9.2.4 帶業務數據的心跳包 690
9.2.5 心跳包與流量 690
9.2.6 心跳包與調試 691
9.2.7 心跳包與日誌 691
9.3 日誌模塊的設計 692
9.3.1 為什麼需要日誌 692
9.3.2 日誌係統的技術實現 692
9.3.3 在C/C++中輸齣網絡數據包日誌 716
9.3.4 調試時的日誌 719
9.3.5 統計程序性能日誌 719
9.3.6 根據類型將日誌寫入不同的文件中 725
9.3.7 集中式日誌服務與分布式日誌服務 725
9.3.8 從業務層麵看在一條日誌中應該包含什麼內容 727
9.3.9 在日誌中不要齣現敏感信息 729
9.3.10 開發過程中的日誌遞進縮減策略 730
9.4 錯誤碼係統的設計 730
9.4.1 錯誤碼的作用 730
9.4.2 錯誤碼係統設計實踐 731
9.5 監控端口 733
· · · · · · (
收起)