Linux系統編程(七)進程間通信IPC

進程間通訊的7種方式_進程間通信的幾種方法-CSDN博客

  1. 管道 pipe(命名管道和匿名管道);
  2. 信號 signal;
  3. 共享內存;
  4. 消息隊列;
  5. 信號量 semaphore;
  6. 套接字 socket;

1. 管道

內核提供,單工,自同步機制。?

1.1 匿名管道

磁盤上無法看到,只能有親緣關系的進程才能用匿名管道。一般用于父子進程間通信。

pipe(2) 系統調用可以創建一個匿名管道 pipefd,文件描述符 pipefd[0] 為讀管道,pipefd[1] 為寫管道。??

#include <unistd.h>int pipe(int pipefd[2]);#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>int pipe2(int pipefd[2], int flags);

例子,父進程通過管道發送 hello 給子進程:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t pid;int pipefd[2];if (pipe(pipefd) < 0) {perror("pipe");exit(1);}pid = fork();if (pid > 0) {// parentclose(pipefd[0]);write(pipefd[1], "hello", 5);close(pipefd[1]);wait(NULL);exit(0);}else if (pid == 0) {// childclose(pipefd[1]);char buf[50];int len = read(pipefd[0], buf, 50);printf("%d\n", len);write(1, buf, len);close(pipefd[0]);exit(0);}else {perror("fork");exit(1);}exit(0);
}

1.2 命名管道

磁盤上能看到,文件類型為 p 的文件。

mkfifo(3) 函數可以創建一個 fifo 特殊文件(命名管道)。

#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);

2 XSI -> SysV

2.1?消息隊列,message queue?

主動端,先發包的一方;被動端,先收包的一方;消息隊列可以用于沒有親緣關系的進程間通信

例子,proto.h,包含了傳遞的內容:

#ifndef PROTO_H__
#define PROTO_H__#define KEYPATH "/etc/services"
#define KEYPROJ 'g'#define NAMESIZE 32struct msg_st
{long mtype;char name[NAMESIZE];int math;int chinese;
};#endif

receiver.c,接收者:

#include <stdio.h>
#include <stdlib.h>
#include "proto.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int main()
{key_t key;int msgid;struct msg_st rbuf;key = ftok(KEYPATH, KEYPROJ);if (key < 0) {perror("ftok");exit(1);}msgid = msgget(key, IPC_CREAT | 0600);if (msgid < 0) {perror("msgget");exit(1);}while (1){if (msgrcv(msgid, &rbuf, sizeof(rbuf) - sizeof(long), 0, 0) < 0){perror("msgrcv");exit(1);}printf("NAME = %s\n", rbuf.name);printf("MATH = %d\n", rbuf.math);printf("CHINESE = %d\n", rbuf.chinese);}msgctl(msgid, IPC_RMID, NULL);exit(0);
}

運行接收者可以看到創建的 msg queue:?

sender.c,發送者:?

#include <stdio.h>
#include <stdlib.h>
#include "proto.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>int main()
{key_t key;struct msg_st sbuf;int msgid;key = ftok(KEYPATH, KEYPROJ);if (key < 0) {perror("ftock");exit(1);}msgid = msgget(key, 0);if (msgid < 0){perror("msgget");exit(1);}sbuf.mtype = 1;strcpy(sbuf.name, "lzp");sbuf.math = 99;sbuf.chinese = 100;if (msgsnd(msgid, &sbuf, sizeof(sbuf) - sizeof(long), 0) < 0) {perror("msgsend");exit(1);}puts("ok!");exit(0);
}

先運行 receiver,然后運行 sender 發送信息:?

2.2 信號量,semaphore arrays

semget、semop、semctl;可以用于沒有親緣關系的進程間通信

2.3 共享內存,shared memory segment

shmget、shmop、shmctl;之前可以通過 mmap 實現共享內存,不過只能在有親緣關系的進程間通信。匿名 ipc 也只能在有親緣關系的進程間通信;

3. 網絡套接字 socket

3.1 跨主機的傳輸

  • 字節序大端存儲(低地址處放高字節)小端存儲(低地址處放低字節,x86);主機字節序(host)和網絡字節序(network);主機序轉網絡序,網絡序轉主機序;htons,htonl,ntohs,ntohl。
  • 對齊:結構體中 char 類型可能會占 4 個字節;如果不對齊,那么 int 類型的存儲地址可能就不是在 4 的倍數的地址上了,可能需要兩次訪存才能取出一個 int 類型。深入理解字節對齊-CSDN博客
  • 類型長度問題:不同主機間的架構,機器字長可能不一樣,結構體類型大小也可能不一樣。解決方案(int32_t,int16_t ...);

socket(2) 系統調用如下:?

#include <sys/types.h>    
#include <sys/socket.h>int socket(int domain, int type, int protocol);
  • domain 指定協議族;
    • AF_INET ? ? ?IPv4 Internet protocols? ? ip(7)
    • AF_INET6 ? ? IPv6 Internet protocols? ?ipv6(7)
  • type 指定通信語義;
    • SOCK_STREAM(流式傳輸):Provides sequenced, reliable, two-way, connection-based byte streams.
    • SOCK_DGRAM(報式傳輸)? :Supports datagrams (connectionless, unreliable messages of a fixed maximum length).
  • protocol 指定協議族中的協議;

bind(2) 系統調用可以給 socket 綁定地址。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

recvfrom(2) 可以從 socket 上接收一條 message:?

#include <sys/types.h>
#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
  1. recv(2) 是用于流式套接字的,是提前建立好連接的,一對一的,點對點的,?不需要記錄對方的 socket 地址;
  2. recvfrom(2) 可以用于報式和流式套接字,每次需要傳入需要通信的 socket 地址;

sendto(2) 函數可以發送 msg 到對應的 socket 地址,可以用于流式和報式傳輸;而?send(2) 函數不需要指定 socket 地址,只能用于事先建立好連接的流式傳輸。

#include <sys/types.h>
#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

3.2 報式套接字(udp)

被動端(先運行)

  1. 取得 socket(socket);
  2. 給 socket 取得地址,相當于綁定本地的地址(bind);
  3. 收/發消息(recvfrom);
  4. 關閉 socket(close);

主動端

  1. 取得 socket;
  2. 給 socket 取得地址(可省略);
  3. 收/發消息;
  4. 關閉 socket;

__attribute__((packed)):packed屬性:使用該屬性可以使得變量或者結構體成員使用最小的對齊方式,即對變量是一字節對齊,對域(field)是位對齊。即不進行對齊。

使用如下指令查看被動段的地址和端口(u代表udp):

netstat -anu

proto.h 約定傳輸格式和內容:?

#ifndef PROTO_H__
#define PROTO_H__#define RCVPORT 1989#define NAMESIZE  11// communication struct
struct msg_st
{char name[NAMESIZE];int math;int ch;
} __attribute__((packed));#endif

receiver.c 接收方, 注意多字節需要使用?ntohl() 來轉換:

#include <stdio.h>
#include <stdlib.h>
#include "proto.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define IPSTRSIZE 40int main()
{int sd; // socket fdstruct sockaddr_in laddr;struct sockaddr_in raddr;struct msg_st rbuf;socklen_t raddr_len;char ipstr[IPSTRSIZE];// IPV4 DGRAM UDPsd = socket(AF_INET, SOCK_DGRAM, 0/* IPPROTO_UDP */);if (sd < 0) {perror("socket");exit(1);}laddr.sin_family = AF_INET;laddr.sin_port = htons(RCVPORT);inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);if (bind(sd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {perror("bindqqq");exit(1);}/* !!! */raddr_len = sizeof(raddr);while (1){recvfrom(sd, &rbuf, sizeof(rbuf), 0, (struct sockaddr *)&raddr, &raddr_len);inet_ntop(AF_INET, &raddr.sin_addr, ipstr, IPSTRSIZE);printf("message from %s:%d---\n", ipstr, ntohs(raddr.sin_port));printf("name = %s\n", rbuf.name);printf("name = %d\n", ntohl(rbuf.math));printf("name = %d\n", ntohl(rbuf.ch));}close(sd);exit(0);
}

sender.c 發送方,發送報文給對應的地址:?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include "proto.h"
#include <unistd.h>int main(int argc, char *argv[])
{int sd;struct msg_st sbuf;struct sockaddr_in raddr;if (argc < 2){fprintf(stderr, "usage..\n");exit(1);}sd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0){perror("socket");exit(1);}//bind();strcpy(sbuf.name, "Alan");sbuf.math = htonl(99);sbuf.ch = htonl(93);raddr.sin_family = AF_INET;raddr.sin_port = htons(RCVPORT);inet_pton(AF_INET, argv[1], &raddr.sin_addr);if (sendto(sd, &sbuf, sizeof(sbuf), 0, (struct sockaddr *)&raddr, sizeof(raddr)) < 0){perror("sendto");exit(1);}puts("ok\n");close(sd);exit(0);
}

運行結果:?

報式套接字還能實現多播、廣播(全網廣播和子網廣播)、組播:

可以通過 getsockopt() 和 setsockopt() 來打開廣播選項。然后將發送的目標地址改成 255.255.255.255 就可以發送廣播了。

多點通信(廣播、多播、組播)只能用報式套接字實現,因為流式套接字是一對一的,點對點的。

udp 會出現丟包的問題,TTL生存周期(路由跳轉個數)?,丟包是由阻塞造成的,當等待隊列快滿的時候會發生丟包(網絡太擁塞),可以使用流量控制解決(限制發送端的速率)。

3.3 流式套接字(tcp)

協議,約定雙方對話的格式。

三次握手容易被ddos攻擊,可以去掉半連接池,然后使用cookie(對方的ip+端口加上我放的ip+端口加上一個內核產生的令牌)。

Client 端和 Server 端:

client:

  1. 獲取 socket;
  2. 給 socket 取得地址;
  3. 發送連接;
  4. 收/發消息;
  5. 關閉連接;

server:

  1. 獲取 socket;
  2. 給 socket 取得地址;
  3. 將 socket 置為監聽模式;
  4. 接受連接;
  5. 收/發消息;
  6. 關閉;

服務端(server.c)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <time.h>
#include "proto.h"#define IPSTRSIZE 40
#define BUFSIZE 1024static void server_job(int sd)
{char buf[BUFSIZE];int len = sprintf(buf, FMT_STAMP, (long long)time(NULL));if (send(sd, buf, len, 0) < 0) {perror("send()");exit(1);}
}int main()
{struct sockaddr_in laddr, raddr;socklen_t raddr_len;char ipstr[IPSTRSIZE];int sd = socket(AF_INET, SOCK_STREAM, 0/* default IPPROTO_TCP */);if (sd < 0) {perror("socket()");exit(1);}laddr.sin_family = AF_INET;laddr.sin_port = htons(atoi(SERVERPORT));inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);if (bind(sd, (void *)&laddr, sizeof(laddr)) < 0) {perror("bind()");exit(1);}// listen for connections on a socketif (listen(sd, 200) < 0){perror("listen()");exit(1);}raddr_len = sizeof(raddr);while (1) {// accept a connection on a socketint newsd;if ((newsd = accept(sd, (void *)&raddr, &raddr_len)) < 0) {perror("accept()");exit(1);}inet_ntop(AF_INET, &raddr.sin_addr, ipstr, IPSTRSIZE);printf("Client: %s : %d\n", ipstr, ntohs(raddr.sin_port));server_job(newsd);// close newsdclose(newsd);}close(sd);exit(0);
}

運行后使用 netstat -ant 可以查看:

當連接被釋放后,服務端會進入一段時間的 timewait 狀態。

客戶端(client.c):

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "proto.h"
int main(int argc, char* argv[])
{struct sockaddr_in raddr;long long stamp;if (argc < 2) {fprintf(stderr, "Usage...\n");exit(1);}int sd = socket(AF_INET, SOCK_STREAM, 0);if (sd < 0) {perror("socket()");exit(1);}// initiate a connection on a socketraddr.sin_family = AF_INET;raddr.sin_port = htons(atoi(SERVERPORT));inet_pton(AF_INET, argv[1], &raddr.sin_addr);if (connect(sd, (void *)&raddr, sizeof(raddr)) < 0) {perror("connect()");exit(1);}FILE* fp = fdopen(sd, "r+");if (fp == NULL) {perror("fdopen()");exit(1);}if (fscanf(fp, FMT_STAMP, &stamp) < 1) {fprintf(stderr, "bad format\n");}else {fprintf(stdout, "stamp = %lld\n", stamp);}fclose(fp);exit(0);
}

上面這種方法有一個缺點,就是假如 server_job 的任務執行時間太長的話,需要等待 server_job 執行完后才能繼續 accept 下一個連接請求,這樣效率十分低,所以可以采用多線程的方式來解決,每個進程或線程處理一個連接請求。

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

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

相關文章

Hive基礎知識(二十三):數據傾斜優化

絕大部分任務都很快完成&#xff0c;只有一個或者少數幾個任務執行的很慢甚至最終執行失敗&#xff0c; 這樣的現象為數據傾斜現象。 一定要和數據過量導致的現象區分開&#xff0c;數據過量的表現為所有任務都執行的很慢&#xff0c;這個 時候只有提高執行資源才可以優化 HQL…

Arduino平臺軟硬件原理及使用——SR04超聲波傳感器的使用

文章目錄&#xff1a; 一、超聲波傳感器工作原理 二、SR04超聲波庫的使用 三、SR04超聲波傳感器在Arduino中的使用 一、超聲波傳感器工作原理 如上圖所示&#xff1a;HCSR04超聲波傳感器擁有4個針腳&#xff0c;除了VCC接正極、GND接負極外&#xff0c;還有兩個引腳“Trig”及“…

Linux線程互斥鎖

目錄 &#x1f6a9;看現象&#xff0c;說原因 &#x1f6a9;解決方案 &#x1f6a9;互斥鎖 &#x1f680;關于互斥鎖的理解 &#x1f680;關于原子性的理解 &#x1f680;如何理解加鎖和解鎖是原子的 &#x1f6a9;對互斥鎖的簡單封裝 引言 大家有任何疑問&#xff0c;可…

【Android面試八股文】如何實現Activity窗口快速變暗

文章目錄 方式一:修改 WindowManager.LayoutParams 的screenBrightness屬性動態調整窗口的亮度方式二:使用 `WindowManager.LayoutParams` 的 `alpha` 屬性結合 `ValueAnimator` 來實現窗口漸變變暗的效果方式三:使用遮罩層在Android中實現Activity窗口快速變暗有幾種方法,…

CCSP自考攻略+經驗總結

備考攻略 備考攻略準備階段通讀階段精度階段總復習階段刷題階段命運審判 寫到最后 備考攻略 趁著對ssp知識點的理解還在&#xff0c;開始ccsp的考證之路&#xff0c;文章結構還是按照cissp備考篇的結構梳理。本次備考和cissp的離職在家備考不同&#xff0c;ccsp是在職利用非工…

如何用亞馬遜合作伙伴網絡快速上線跨境電商

目前跨境電商已成為行業發展主流&#xff0c;如何快速、低成本打造品牌海外獨立站和智能客服營銷中心、構建全鏈路跨境電商體系是出海電商商家都會遇到的難題。亞馬遜云科技憑借與亞馬遜電商平臺易于集成的先天優勢成為首選的電商解決方案平臺。本文介紹了如何用亞馬遜云科技平…

Elasticsearch8.x聚合查詢全面指南:從理論到實戰

聚合查詢的概念 聚合查詢&#xff08;Aggregation Queries&#xff09;是Elasticsearch中用于數據匯總和分析的查詢類型。它不同于普通的查詢&#xff0c;而是用于執行各種聚合操作&#xff0c;如計數、求和、平均值、最小值、最大值、分組等。 聚合查詢的分類 分桶聚合&…

centos7 安裝單機MongoDB

centos7安裝單機 yum 安裝 1、配置yum源 vim /etc/yum.repos.d/mongodb.repo [mongodb-org-7.0] nameMongoDB Repository baseurlhttps://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/7.0/x86_64/ gpgcheck1 enabled1 gpgkeyhttps://www.mongodb.org/static/pgp…

【監控】3.配置 Grafana 以使用 Prometheus 數據源

1 訪問 Grafana 打開瀏覽器&#xff0c;訪問 http://localhost:3000&#xff08;默認端口&#xff09;。使用默認的用戶名和密碼 admin/admin 登錄。 2 添加 Prometheus 數據源 進入 Grafana 儀表板&#xff0c;點擊左側菜單中的“Configuration” -> “Data Sources”。…

未來已來,如何打造智慧養殖場?

近年來&#xff0c;國家出臺了一系列扶持政策&#xff0c;以促進養殖行業高質量發展&#xff0c;推動行業轉型升級。在國家政策和市場需求的雙重驅動下&#xff0c;養殖行業正迎來前所未有的發展機遇。智慧養殖以其高效、智能和可持續的特點&#xff0c;正逐步取代傳統養殖方式…

6.26.4.1 基于交叉視角變換的未配準醫學圖像多視角分析

1. 介紹 許多醫學成像任務使用來自多個視圖或模式的數據&#xff0c;但很難有效地將這些數據結合起來。雖然多模態圖像通常可以在神經網絡中作為多個輸入通道進行配準和處理&#xff0c;但來自不同視圖的圖像可能難以正確配準(例如&#xff0c;[2])。因此&#xff0c;大多數多視…

電影搜索筆記

1 字幕組 2 磁力搜索 2.1 磁力大全 http://7809.org/cldq.html

吳恩達2022機器學習專項課程C2W3:2.27 選修_數據傾斜

目錄 處理不平衡數據集1.分類需求描述2.計算精確率和召回率 權衡精確率和召喚率1.手動調整閾值2.F1分數 總結 處理不平衡數據集 1.分類需求描述 如果你在處理一個機器學習應用&#xff0c;其中正例和負例的比例&#xff08;用于解決分類問題&#xff09;非常不平衡&#xff0…

多域名微信公眾號獲取授權(前后端分離,后端獲取微信用戶openid)

1.通過后端站點http://b.cn 跳轉至前端鏈接 http://aa.cn/v1/demo/demo public function index(){$identinput(ident);$this->redirect(http://aa.cn/?ident.$ident);}2.前端http://aa.cn 再跳轉到后端 https://c.com(此域名綁定微信公眾號:需備案) onShow() {console.lo…

數據庫怎么同步

數據庫要怎么同步呢&#xff0c;有很多方法&#xff0c;看你用什么數據庫&#xff0c;如果是Sqlserver,你要數據庫同步&#xff0c;那么可以使用自帶的訂閱發布&#xff0c;訂閱發布應該是不錯的方法&#xff0c;但是我上次要配置雙向同步&#xff0c;它的對等發布好像沒部署成…

Ansible-綜合練習-生產案例

斌的招兒 網上教程大多都是官網模板化的教程和文檔&#xff0c;這里小斌用自己實際生產環境使用的例子給大家做一個詳解。涉及到一整套ansible的使用&#xff0c;對于roles的使用&#xff0c;也僅涉及到tasks和files目錄&#xff0c;方便大家快速上手并規范化管理。 0.環境配置…

想關掉一個qwidget是用deleteLater還是用close

在Qt中關閉一個QWidget可以選擇使用close()或者deleteLater()兩種方法&#xff0c;根據具體需求&#xff0c;兩者有不同的適用場景&#xff1a; close()方法&#xff1a; close()會觸發QWidget的closeEvent&#xff0c;也就是說&#xff0c;它會產生一個關閉事件&#xff0c;可…

聚星文社AI工具

聚星文社AI工具是一種基于人工智能技術開發的工具&#xff0c;旨在輔助作者和寫作人員提升創作效率和質量。 點擊下載 該工具可以提供多項功能&#xff0c;包括語法糾錯、智能推薦、文章自動摘要等。 通過使用聚星文社AI工具&#xff0c;用戶可以在寫作過程中得到即時的糾錯建…

memcached服務介紹

memcached 基礎概念安裝使用 基礎概念 Memcached 是一個高性能的分布式內存對象緩存系統&#xff0c;用于減少數據庫負載&#xff0c;加速動態 Web 應用。 Memcached 的基本概念 緩存&#xff1a;Memcached 的核心功能是緩存數據&#xff0c;它將經常訪問的數據存儲在內存中…