Linux網路編程--進程間通信(一)

来源:http://www.cnblogs.com/lang5230/archive/2016/05/17/5502771.html
-Advertisement-
Play Games

進程間通信簡介(摘自《Linux網路編程》p85) AT&T 在 UNIX System V 中引入了幾種新的進程通訊方式,即消息隊列( MessageQueues),信號量( semaphores)和共用記憶體( shared memory),統稱為 System V IPC。在Linux 系統編程 ...


進程間通信簡介(摘自《Linux網路編程》p85)

  AT&T 在 UNIX System V 中引入了幾種新的進程通訊方式,即消息隊列( MessageQueues),信號量( semaphores)和共用記憶體( shared memory),統稱為 System V IPC。在Linux 系統編程中,它們有著廣泛的應用。
  System V IPC 的一個顯著的特點,是它的具體實例在內核中是以對象的形式出現的,我們稱之為 IPC 對象。每個 IPC 對象在系統內核中都有一個唯一的標識符。通過標識符內核可以正確的引用指定的 IPC 對象.。需要註意的是,標識符的唯一性只在每一類的 IPC 對象內成立。比如說,一個消息隊列和一個信號量的標識符可能是相同的,但絕對不會出現兩個有相同標識符的消息隊列。

  標識符只在內核中使用, IPC 對象在程式中是通過關鍵字( key)來訪問的。和 IPC 對象標識符一樣,關鍵字也必須是唯一的。而且,要訪問同一個 IPC 對象, Server 和 Client必須使用同一個關鍵字。因此,如何構造新的關鍵字使之不和已有的關鍵字衝突,並保證Server 和 Client 使用的關鍵字是相同的,是建立 IPC 對象時首先要解決的一個問題。(具體在後邊的msg通信中詳解)

通信方法還有:半雙工管道pipe,命名管道fifo,消息隊列,信號量,共用內,socket套接字等,下麵一一介紹:

半雙工管道:

  int pipe(int filedes[2]);

  管道是將兩個進程之間的標準輸入輸出相互對接的機制

  linux命令中使用的管道 |  : ls -l | grep *.c  //顯示文件(輸入端)-(|)-(輸出端)>找到.c結尾文件

實現:因為半雙工緣故,所以只能實現一段輸入,一段輸出,而不能雙向通信。所以:實現為,通過管道連接進程,一端開放讀文件描述,一端開放寫文件描述

//管道的性質就是,一個進程的輸出作為另一個進程的輸入
//那麼我們可以關閉一個進程讀端使之作為輸入端,
//另一個進程關閉寫端,讀取數據,接收數據作為管道輸出端

//FIFO命名管道
//文件系統中,命名管道是特殊文件的方式存在的
//不同進程可以通過命名管道共用數據

//命名管道一直是阻塞方式的,且必須是顯示的通過open建立連接到管道的通道
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#include<sys/types.h>

int main()
{
    int result = 1;
    int fd[2];
    pid_t pid;
    int *write_fd = &fd[1];        //寫文件描述
    int *read_fd = &fd[0];        //讀文件描述
    
    int nbytes;
    char str[] = "管道,你好\n";    
    char readBuffer[80];
    memset(readBuffer,0,sizeof(readBuffer));

    result = pipe(fd);        //創建管道
    if(-1==result)
    {
        printf("管道創建失敗!\n");
        return -1;
    }
    
    pid = fork();            //進程創建分叉程式
    if(-1 == pid)
    {
        printf("fork失敗");
        return -1;
    }

    if(0==pid)            //子進程關閉讀端,寫入字元
    {
        close(*read_fd);
        result = write(*write_fd,str,strlen(str));
        printf("寫入%d個數據\n",result);
    }
    else                //父進程關閉寫端,讀取數據
    {
        close(*write_fd);
        nbytes = read(*read_fd,readBuffer,sizeof(readBuffer));
        printf("接收到%d個數據,內容為%s",nbytes,readBuffer);
    }
    return 0;
}

②命名管道

  int mkfifo(const char* pathname,mode_t mode);

  類似於普通管道,只是

  a.在文件系統中以設備特殊文件的形式存在

  b.不同進程之間可以通過命名管道共用數據

操作區別於普通管道:FIFO中必須顯式通過open建立連接到管道的通道,且總是處於阻塞狀態的

消息隊列

  消息隊列是內核地址空間的內部鏈表,通過內核在各個進程之間傳遞內容。每個消息隊列通過唯一IPC標識符標識,不同隊列相對獨立。

  

//file: msg.h
/*
message buffer for msgsnd and msgrcv calls */ struct msgbuf { __kernel_long_t mtype; /* type of message */ char mtext[1]; /* message text */ }; /* Obsolete, used only for backwards compatibility and libc5 compiles */ struct msqid_ds { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue,unused */ struct msg *msg_last; /* last message in queue,unused */ __kernel_time_t msg_stime; /* last msgsnd time */ __kernel_time_t msg_rtime; /* last msgrcv time */ __kernel_time_t msg_ctime; /* last change time */ unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ unsigned long msg_lqbytes; /* ditto */ unsigned short msg_cbytes; /* current number of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ unsigned short msg_qbytes; /* max number of bytes on queue */ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ };
//filename
/*
Obsolete, used only for backwards compatibility and libc5 compiles */ struct ipc_perm { __kernel_key_t key;  //函數msgget()使用的鍵值   __kernel_uid_t uid;  //用戶UID __kernel_gid_t gid;  //用戶GID __kernel_uid_t cuid;  //創建者UID __kernel_gid_t cgid;  //創建者GID __kernel_mode_t mode;   //許可權 unsigned short seq;  //序列號 };

  內核中的消息隊列

註:結構list_head 形成一個鏈表,結構msg_msg之中的m_list使得消息形成鏈表,查找,插入時,對m_list域進行偏移找到位置

相關函數:

  鍵值構建 key_t ftok(const char* pathname,int proj_id);

  獲取消息 int msgget(key_t key,int msgflg);

  發送消息 int msgsnd(int msqid, const void * msgp,size_t msgsz,int msgflg);

  接收消息 ssize_t msgrcv(int msqid, void * msgp, size_t msgsz, long msgtype, int msgflg);

  消息控制 int msgctl(int msqid, int cmd, struct msqid_ds *buf);  //向內核發送cmd命令判斷進行何種操作

一個簡單例子

④信號量

  信號量是一種計數器,用來控制對多個進程共用的資源所進行的訪問。常用作鎖機制(生產者消費者模型是個典型使用)

  信號量結構

//filename sys/sem.h
/*
arg for semctl system calls. */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ unsigned short *array; /* 數組結構 */ struct seminfo *__buf; /* 信號量內部結構 */ void *__pad; };

  相關函數 

  新建信號量 int semget(key_t key, int nsems, int semflg);

  //key 來自於ftok()

  信號量操作函數 int semop(int semid,struct sembuf* sops, unsigned nsops);

  //信號量的P,V操作通過向已經建立好的信號量發送命令完成

  控制信號量參數

  int semctl(int semid, int semnum ,int cmd,.....);

  //用於在信號量集合上執行控制操作

#include<stdio.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h>

typedef int sem_t;
union semun
{
    int val;
    struct semid_ds * buf;
    unsigned short *array;
}arg;

sem_t CreateSem(key_t key, int value)
{
    union semun sem;
    sem_t semid;
    sem.val = value;
    
    semid = semget(key,0,IPC_CREAT);
    if(-1 == semid)
    {
        printf("create semaphore error\n");
        return -1;
    }
    
    semctl(semid,0,SETVAL,sem);
    
    return semid;
}

int Sem_P(sem_t semid)
{
struct sembuf sops = {0,+1,IPC_NOWAIT};
return (semop(semid,&sops,1));
}

int Sem_V(sem_t semid)
{
    struct sembuf sops = {0,-1,IPC_NOWAIT};
    return (semop(semid,&sops,1));
}

void SetvalueSem(sem_t semid , int value)
{
    union semun sem;
    sem.val = value;
    semctl(semid,0,SETVAL,sem);
}

int GetvalueSem(sem_t semid)
{
    union semun sem;
    return semctl(semid,0,GETVAL,sem);
}

void DestroySem(sem_t semid)
{
    union semun sem;
    sem.val = 0;
    semctl(semid,0,IPC_RMID,sem);
}
int main()
{
    key_t key;
    int semid;
    char i;
    int value = 0;
    key = ftok("/ipc/sem",'a');
    
    semid = CreateSem(key,100);
    for( i = 0;i <= 3;++i)
    {
        Sem_P(semid);
        Sem_V(semid);    
    }
    value = GetvalueSem(semid);    
    
    DestroySem(semid);    
    return 0;
}

⑤共用記憶體(最快捷的方法)沒有中間過程,管道等

  在多個進程之間共用記憶體區域的一種進程間通信方式,在多個進程之間對記憶體段進行映射的方式實現記憶體共用。

    相關函數

  創建共用記憶體函數 int shmget(key_y key, size_t size, int shmflg);

  獲得共用記憶體地址void * shmat(int shmid,const void* shmaddr, int shmflg);

  刪除共用記憶體函數 int shmdt(const void* shmadddr);

  共用記憶體控制函數 int shmctl(int shmid ,int cmd, struct shmid_ds * buf);

⑥信號

  用於在一個或多個進程之間傳遞非同步信號。

  相關函數

  信號截取 sighandler signal(int signum ,sighandler handler);

  發送信號 int kill(pid_t pid, int sig);

       int raise(int sig);

  

  

  

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、準備工作 1.1、創建 zhuzz/tools目錄 1.2、將cmake-2.8.8.tar.gz|mysql-5.5.32.tar 上傳至 zhuzz/tools目錄 1.3、解壓cmake安裝包 [root@localhost tools]# tar xf cmake-2.8.8.tar.g ...
  • 檢查配置文件/etc/my.cnf發現供應商修改了mysql資料庫的數據存儲目錄,另外mysql.sock文件位置也變更為了/dat/data/mysql/mysql.sock 第一種方法,修改my.cnf的配置項,修改到'/var/lib/mysql/mysql.sock‘第二種方法:建立mysq ...
  • 如果你會查詢這些相關的問題,說明你是一個正在或者準備從事IT的程式猿,對於一個程式猿而言,不會使用linux系統的程式猿不是一好的程式猿哦!因為windows有時候真的讓人很抓狂,而本人也相信沒有什麼習慣是不可以改變的。so以下都是在linux系統中的使用: 安裝mysql命令 :$ sudo ap ...
  • 很多時候,當我執行查詢調優的時候,引發查詢性能糟糕的問題一般都是與參數化相關的。 一方面,參數化是查詢處理器核心的基本主題。它能顯著影響查詢性能。另一方面,大家很少對這一主題進行詳盡的瞭解。 因此我準備寫一個系列的隨筆來介紹關於參數化的問題。第一篇我將介紹關於計劃緩存的內容。為了理解參數化,有必要先 ...
  • 前言 前面[關係資料庫SQL之可編程性函數(用戶自定義函數)][1]一文提到關係型資料庫提供了可編程性的函數、存儲過程、事務、觸發器及游標,前文已介紹了函數、存儲過程、事務,本文來介紹一下觸發器的使用。( 還是以前面的銀行系統為例 ) ![圖片來自網路][0] 概述 觸發器(TRIGGER)是個特殊 ...
  • 記錄了通過sqlalchemy 管理db2資料庫的環境搭建 1.db2資料庫安裝配置 利用winscp複製iso文件到/mnt/IBM_db2 目錄下 IBM_db2為自己創建 重命名 mv IBM\ DB2\ Enterprise\ Server\ Edition_v9.7\ for\ Linux ...
  • 零、resource http://pan.baidu.com/s/1o83r3S2 一、centos 6.4、VirtualBox 5.0.14 二、nginx 1.9.9 安裝 [root@pc ~]# cd /usr/local/src/ [root@pc src]# yum install ...
  • ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...