UNIX 域套接字實現本地進程間通信

🚀 使用 UNIX 域套接字 (AF_UNIX) 實現高效進程通信

在 Linux 和其他類 UNIX 系統中,進程間通信 (IPC) 的方法有很多種,例如管道、消息隊列、共享內存等。然而,當你的應用程序需要在 同一臺機器上的不同進程間進行高效、低延遲的數據交換時,UNIX 域套接字 (AF_UNIX) 往往是最佳選擇。
它的工作方式類似于網絡套接字,但所有數據傳輸都發生在內核內部,避免了網絡協議棧的開銷,因此速度更快、效率更高。


💡 為什么選擇 UNIX 域套接字?

在深入代碼之前,我們先來聊聊 AF_UNIX 的優勢:

  1. 高性能:數據在內核中直接傳遞,無需經過網絡層,減少了數據復制和上下文切換,顯著提升了通信速度。
  2. 低延遲:由于沒有網絡開銷,通信延遲極低,非常適合對實時性要求高的應用。
  3. 安全性:UNIX 域套接字在文件系統中表現為一個特殊文件。這意味著你可以使用標準的文件權限來控制哪些用戶或進程可以訪問它,提供了比某些其他 IPC 機制更細粒度的安全控制。
  4. API 熟悉度:如果你熟悉網絡套接字(AF_INET),那么AF_UNIX 的 API會讓你感到非常親切。socket(), bind(), listen(), accept(), connect(), read(), write() 等函數都通用,降低了學習成本

🛠? 如何工作?(核心概念)

UNIX 域套接字的運作方式很直觀:

  1. 文件路徑作為地址:與網絡套接字使用 IP 地址和端口號不同,AF_UNIX 套接字使用文件系統路徑作為其唯一的標識符。服務器會綁定到一個特定的文件路徑(例如 /tmp/my_socket),客戶端則通過這個路徑來連接服務器。

  2. 服務器端:
    創建一個 AF_UNIX 類型的套接字。
    將套接字綁定到文件系統中的一個路徑。這個操作會在指定路徑下創建一個特殊的套接字文件。
    開始監聽傳入的連接請求。
    接受客戶端的連接,每次接受都會返回一個新的套接字文件描述符,用于與該客戶端單獨通信。
    使用 read()write() 進行數據傳輸。

  3. 客戶端:
    創建一個 AF_UNIX 類型的套接字。
    連接到服務器綁定的文件路徑。
    使用read() write() 進行數據傳輸。


🧑?💻 代碼實戰:構建一個簡單的 Echo 服務器

下面將通過 C 語言代碼,一步步實現一個 UNIX 域套接字服務器和對應的客戶端。服務器將接收客戶端發送的消息,并原樣返回(Echo)。

  1. 服務器端 (server.c)
    服務器的職責是創建、綁定、監聽并接受連接,然后處理數據
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h> // 包含 sockaddr_un 結構體
#include <unistd.h>#define SOCKET_PATH "/tmp/my_unix_socket" // 服務器將綁定的套接字文件路徑
#define BUFFER_SIZE 256int main() {int server_fd, client_fd;struct sockaddr_un server_addr, client_addr;socklen_t client_len;char buffer[BUFFER_SIZE];int bytes_read;// 1. 創建UNIX域套接字 (AF_UNIX, 流式套接字 SOCK_STREAM)server_fd = socket(AF_UNIX, SOCK_STREAM, 0);if (server_fd == -1) {perror("socket");exit(EXIT_FAILURE);}// 2. 設置服務器地址結構體memset(&server_addr, 0, sizeof(server_addr));server_addr.sun_family = AF_UNIX;// 將套接字路徑復制到 sun_path 字段strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);// 3. 重要的清理步驟:刪除舊的套接字文件(如果存在)// 如果服務器上次異常退出,可能留下這個文件,導致綁定失敗unlink(SOCKET_PATH); // 4. 將套接字綁定到指定的文件路徑if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("bind");close(server_fd);exit(EXIT_FAILURE);}// 5. 開始監聽連接請求,隊列長度為 5if (listen(server_fd, 5) == -1) {perror("listen");close(server_fd);exit(EXIT_FAILURE);}printf("🚀 服務器已啟動,監聽在 %s...\n", SOCKET_PATH);while (1) {client_len = sizeof(client_addr);// 6. 接受新的客戶端連接,這是一個阻塞調用client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);if (client_fd == -1) {perror("accept");continue; // 繼續等待下一個連接}printf("🤝 接受到一個新連接。\n");// 7. 與客戶端進行數據通信(Echo 功能)while ((bytes_read = read(client_fd, buffer, sizeof(buffer) - 1)) > 0) {buffer[bytes_read] = '\0'; // 確保字符串以 null 結尾printf("?? 接收到客戶端消息: %s", buffer);// 將收到的消息原樣回傳給客戶端if (write(client_fd, buffer, bytes_read) == -1) {perror("write");break; // 寫入失敗則退出循環}printf("?? 已回復客戶端。\n");}if (bytes_read == -1) {perror("read");} else if (bytes_read == 0) {printf("🔴 客戶端已關閉連接。\n");}// 8. 關閉與當前客戶端的連接close(client_fd);}// 9. 關閉服務器監聽套接字,并清理套接字文件(通常在程序退出時執行)close(server_fd);unlink(SOCKET_PATH); return 0;
}
  1. 客戶端 (client.c)
    客戶端負責創建套接字并連接到服務器,然后發送和接收數據。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h> // 包含 sockaddr_un 結構體
#include <unistd.h>#define SOCKET_PATH "/tmp/my_unix_socket" // 服務器的套接字文件路徑
#define BUFFER_SIZE 256int main() {int client_fd;struct sockaddr_un server_addr;char buffer[BUFFER_SIZE];int bytes_read;// 1. 創建UNIX域套接字client_fd = socket(AF_UNIX, SOCK_STREAM, 0);if (client_fd == -1) {perror("socket");exit(EXIT_FAILURE);}// 2. 設置服務器地址結構體memset(&server_addr, 0, sizeof(server_addr));server_addr.sun_family = AF_UNIX;strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);// 3. 連接到服務器if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("connect");close(client_fd);exit(EXIT_FAILURE);}printf("? 成功連接到服務器。\n");// 4. 與服務器進行數據通信while (1) {printf("請輸入消息(輸入 'exit' 退出): ");if (fgets(buffer, sizeof(buffer), stdin) == NULL) {break; // 讀取失敗或EOF}// 檢查用戶是否輸入 'exit'if (strcmp(buffer, "exit\n") == 0) {break;}// 將消息發送給服務器if (write(client_fd, buffer, strlen(buffer)) == -1) {perror("write");break;}// 從服務器接收回復bytes_read = read(client_fd, buffer, sizeof(buffer) - 1);if (bytes_read == -1) {perror("read");break;} else if (bytes_read == 0) {printf("🚫 服務器已關閉連接。\n");break;}buffer[bytes_read] = '\0'; // 確保字符串以 null 結尾printf("?? 收到服務器回復: %s", buffer);}// 5. 關閉客戶端套接字close(client_fd);printf("👋 客戶端已退出。\n");return 0;
}

🖥? 編譯與運行

在你的 Linux 終端中,按照以下步驟編譯和運行:

編譯服務器和客戶端:

gcc server.c -o server
gcc client.c -o client

啟動服務器:
打開一個終端窗口,運行服務器程序。

./server

你應該會看到輸出 🚀 服務器已啟動,監聽在 /tmp/my_unix_socket…

啟動客戶端:
打開另一個終端窗口,運行客戶端程序。

./client

客戶端會顯示 ? 成功連接到服務器。

現在,你可以在客戶端終端輸入消息,服務器會接收到并將其原樣返回給客戶端!


🧹 清理注意事項

UNIX 域套接字文件 (/tmp/my_unix_socket 在我們的例子中) 會在服務器綁定時創建。如果服務器非正常退出 (例如,被 Ctrl+C 中斷),這個文件可能不會被自動刪除。下次你嘗試啟動服務器時,可能會遇到 “Address already in use” (地址已被占用) 的錯誤。

這就是為什么在服務器代碼中,我們特意加入了 unlink(SOCKET_PATH); 這一行。它確保在綁定新套接字之前,刪除任何可能殘留的舊套接字文件,從而避免啟動失敗。

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

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

相關文章

【Axure教程】中繼器間圖片的傳遞

中繼器在Axure中可以作為圖片保存的數據庫&#xff0c;在實際系統中&#xff0c;我們經常需要將選擇數據庫的圖片添加到其他圖片列表中&#xff0c;所以今天就教大家&#xff0c;怎么在Axure中實現中繼器之間的圖片傳遞&#xff0c;包含將一個中繼器中的圖片列表傳遞到另一個中…

專題:2025云計算與AI技術研究趨勢報告|附200+份報告PDF、原數據表匯總下載

原文鏈接&#xff1a;https://tecdat.cn/?p42935 關鍵詞&#xff1a;2025, 云計算&#xff0c;AI 技術&#xff0c;市場趨勢&#xff0c;深度學習&#xff0c;公有云&#xff0c;研究報告 云計算和 AI 技術正以肉眼可見的速度重塑商業世界。過去十年&#xff0c;全球云服務收…

從代碼學習深度強化學習 - PPO PyTorch版

文章目錄 前言PPO 算法簡介從 TRPO 到 PPOPPO 的兩種形式:懲罰與截斷代碼實踐:PPO 解決離散動作空間問題 (CartPole)環境與工具函數定義策略與價值網絡PPO 智能體核心實現訓練與結果代碼實踐:PPO 解決連續動作空間問題 (Pendulum)環境準備適用于連續動作的網絡PPO 智能體 (連…

PortsWiggerLab: Blind OS command injection with output redirection

實驗目的This lab contains a blind OS command injection vulnerability in the feedback function.The application executes a shell command containing the user-supplied details. The output from the command is not returned in the response. However, you can use o…

星云穿越與超光速飛行特效的前端實現原理與實踐

文章目錄 1,引言2,特效設計思路3,技術原理解析1. 星點的三維分布2. 視角推進與星點運動3. 三維到二維的投影4. 星點的視覺表現5. 色彩與模糊處理4,關鍵實現流程圖5,應用場景與優化建議6,總結1,引言 在現代網頁開發中,炫酷的視覺特效不僅能提升用戶體驗,還能為產品增添…

【Linux】C++項目分層架構:核心三層與關鍵輔助

C 項目分層架構全指南&#xff1a;核心三層 關鍵輔助一、核心三層架構 傳統的三層架構&#xff08;或三層體系結構&#xff09;是構建健壯系統的基石&#xff0c;包括以下三層&#xff1a; 1. 表現層&#xff08;Presentation Layer&#xff09; 負責展示和輸入處理&#xff0…

【機器學習】保序回歸平滑校準算法

保序回歸平滑校準算法&#xff08;SIR&#xff09;通過分桶合并線性插值解決廣告預估偏差問題&#xff0c;核心是保持原始排序下糾偏。具體步驟&#xff1a;1&#xff09;按預估分升序分桶&#xff0c;統計每個分桶的后驗CTR&#xff1b;2&#xff09;合并逆序桶重新計算均值&a…

項目開發日記

框架整理學習UIMgr&#xff1a;一、數據結構與算法 1.1 關鍵數據結構成員變量類型說明m_CtrlsList<PageInfo>當前正在顯示的所有 UI 頁面m_CachesList<PageInfo>已打開過、但現在不顯示的頁面&#xff08;緩存池&#xff09; 1.2 算法邏輯查找緩存頁面&#xff1a;…

60 美元玩轉 Li-Fi —— 開源 OpenVLC 平臺入門(附 BeagleBone Black 驅動簡單解析)

60 美元玩轉 Li-Fi —— 開源 OpenVLC 平臺入門&#xff08;附 BeagleBone Black 及驅動解析&#xff09;一、什么是 OpenVLC&#xff1f; OpenVLC 是由西班牙 IMDEA Networks 研究所推出的開源可見光通信&#xff08;VLC / Li-Fi&#xff09;研究平臺。它把硬件、驅動、協議棧…

Python性能優化

Python 以其簡潔和易用性著稱,但在某些計算密集型或大數據處理場景下,性能可能成為瓶頸。幸運的是,通過一些巧妙的編程技巧,我們可以顯著提升Python代碼的執行效率。本文將介紹8個實用的性能優化技巧,幫助你編寫更快、更高效的Python代碼。   一、優化前的黃金法則:先測…

easyui碰到想要去除頂部欄按鈕邊框

只需要加上 plain"true"<a href"javascript:void(0)" class"easyui-linkbutton" iconCls"icon-add" plain"true"onclick"newCheck()">新增</a>

C++字符串詳解:原理、操作及力扣算法實戰

一、C字符串簡介在C中&#xff0c;字符串的處理方式主要有兩種&#xff1a;字符數組&#xff08;C風格字符串&#xff09;和std::string類。雖然字符數組是C語言遺留的底層實現方式&#xff0c;但現代C更推薦使用std::string類&#xff0c;其封裝了復雜的操作邏輯&#xff0c;提…

CMU15445-2024fall-project1踩坑經歷

p1目錄&#xff1a;lRU\_K替換策略LRULRU\_K大體思路SetEvictableRecordAccessSizeEvictRemoveDisk SchedulerBufferPoolNewPageDeletePageFlashPage/FlashAllPageCheckReadPage/CheckWritePagePageGuard并發設計主邏輯感謝CMU的教授們給我們分享了如此精彩的一門課程&#xff…

【C語言進階】帶你由淺入深了解指針【第四期】:數組指針的應用、介紹函數指針

前言上一期講了數組指針的原理&#xff0c;這一期接著上一期講述數組指針的應用以及數組參數、函數參數。首先看下面的代碼進行上一期內容的復習&#xff0c;pc應該是什么類型&#xff1f;char* arr[5] {0}; xxx pc &arr;分析&#xff1a;①首先判斷arr是一個數組&#x…

在HTML中CSS三種使用方式

一、行內樣式在標簽<>中輸入style "屬性&#xff1a;屬性值;"。(中等使用頻率)不利于CSS樣式的復用&#xff1b;違背了CSS內容和樣式分離的設計理念&#xff0c;后期難以維護。<p style"color: red">這是div中的p元素</p>二、內部樣式在…

汽車功能安全-軟件單元驗證 (Software Unit Verification)【用例導出方法、輸出物】8

文章目錄1 軟件單元驗證用例導出方法2 測試用例完整性度量標準3 驗證環境要求4 軟件單元驗證的工作產品1 軟件單元驗證用例導出方法 為確保軟件單元測試的測試案例規范符合9.4.2要求&#xff0c;應通過表8所列方法開發測試用例。 表8 軟件單元測試用例的得出方法&#xff1a; …

MySQL內置函數(8)

文章目錄前言一、日期函數二、字符串函數三、數學函數四、其它函數總結前言 其實在之前的幾篇中我們也用到了內置函數&#xff0c;現在我們再來系統學習一下它&#xff01; 一、日期函數 函數名稱描述current_date()獲取當前日期current_time()獲取當前時間current_timestamp(…

蒼穹外賣項目日記(day04)

蒼穹外賣|項目日記(day04) 前言: 今天主要是接口開發, 涉及的新東西不多, 需要注意的只有多表聯查和修改的邏輯,今日難點: 1.菜品的停起售狀態設置 2.套餐的停起售狀態設置 3.動態sql中的 useGeneratedKeys 與 keyProperty 兩個參數 一. 菜品的停起售狀態設置 ? 在菜品的停售中…

React之旅-05 List Key

每個React的初學者&#xff0c;在調試程序時&#xff0c;都會遇到這樣的警告&#xff1a;Warning: Each child in a list should have a unique "key" prop. 如下面的代碼&#xff1a; const list [Learn React, Learn GraphQL];const ListWithoutKey () > (&l…

[特殊字符] 人工智能技術全景:從基礎理論到前沿應用的深度解析

&#x1f680; 人工智能技術全景&#xff1a;從基礎理論到前沿應用的深度解析 在這個AI驅動的時代&#xff0c;理解人工智能的核心技術和應用場景已成為技術人員的必備技能。本文將帶你深入探索AI的發展脈絡、核心技術差異以及在各行業的創新應用。 文章目錄&#x1f680; 人工…