1. 程式人生 > >詳解Linux中程序間的常用通訊方式

詳解Linux中程序間的常用通訊方式

1、無名管道(Pipe)及有名管道(Named Pipe)

——管道是Linux中基於檔案描述符的程序間通訊方式之一,它把一個程式的輸出直接連線到另一個程式的輸入。

無名管道:用於具有親緣關係程序間的通訊。  (不常用) 特點:
  • 僅用於父子或者兄弟程序之間通訊
  • 半雙工通訊(有固定的讀端和寫端)
  • 一種特殊檔案(可使用read()、write()等函式,但不屬於其它檔案系統且僅存在於記憶體中)。
管道建立函式—— pipe(int fd[2]) 函式傳入值 fd[2]: 管道的兩個檔案描述符 返回值:成功 0 失敗 -1 管道讀寫注意事項:
  • 只有在管道的讀端存在時,向管道寫入資料才有意義。否則會收到核心傳來的SIGPIPE訊號。
  • 向管道寫入資料時, Linux將不保證寫入的原子性,管道緩衝區有空閒區域,寫程序就會試圖向管道寫入資料,如果讀程序不讀取管道緩衝區中的資料,那麼寫操作會一直阻塞。
  • 父子程序在執行時,先後順序不能保證。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

#define MAX_DATA_LEN 256
#define DELAY_TIME 1

int main()
{
	pid_t pid;
	int pipe_fd[2];
	char buf[MAX_DATA_LEN];
	const char data[] = "Pipe Test Program";
	int real_read, real_write;
	
	memset((void*)buf, 0, sizeof(buf));
	if(pipe(pipe_fd) < 0)
	{
		printf("pipe create error\n");
		exit(1);
	}
	
	if((pid = fork()) == 0)
	{
	/* Child process close read fd and suspend for 1s until father process have closed corresponding fd */
		close(pipe_fd[1]);
		sleep(DELAY_TIME);
		/* Child process read pipe content */
		if((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0)
		{
			printf("%d bytes read from the pipe is '%s'\n", real_read, buf);
		}
		close(pipe_fd[0]); /* Close child process read fd*/
		exit(0);
	}
	else if(pid > 0)
	{
		close(pipe_fd[0]);
		sleep(DELAY_TIME);
		if((real_write = write(pipe_fd[1], data, strlen(data))) != -1)
		{
			printf("Parent wrote %d bytes: '%s'\n", real_write, data);
		}
		close(pipe_fd[1]);
		waitpid(pid, NULL, 0);		/* Collect info of child process when exit.*/
		exit(0);
	}
	
	return 0;
}
標準流管道:基於檔案流標準I/O模式的管道,主要用來建立一個連線到“另一個程序”的管道,另一個程序即指一個可以進行另一個操作的可執行檔案。(較常用) 常用函式:popen()、 pclose(); note: 使用popen()建立的管道必須使用標準I/O函式進行操作,不能使用前面的 read()、write()一類不帶緩衝的函式。
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BUFSIZE 1024

int main()
{
	FILE *fp;
	char* cmd = "ps -ef";
	char buf[BUFSIZE];
	
	if((fp = popen(cmd, "r")) == NULL)
	{
		printf("Popen error\n");
		exit(1);
	}

	while((fgets(buf, BUFSIZE, fp)) != NULL)
	{
		printf("%s\n", buf);
	}
	pclose(fp);

	exit(0);
}

有名管道:既具有管道具有的功能,也可以允許非無親緣關係程序間的通訊。 特點:
  • 可用於互不相關的兩個程序間通訊
  • 可以通過路徑名來指出且在檔案系統中可見
  • FIFO嚴格遵循先進先出原則,對管道及FIFO的讀總是從開始處返回資料,寫則總是將資料新增到末尾,不支援如lseek()等檔案定位操作。
以下包括兩個採用阻塞式讀寫管道模式的程式fifo_read.c 和fifo_write.c,讀管道程式中建立管道,讀出由使用者寫入到管道中的內容;寫管道程式要寫的內容作為main()的引數傳遞給寫管道程式。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#define MYFIFO "/tmp/myfifo"	/* 有名管道檔名*/
#define MAX_BUFFER_SIZE PIPE_BUF /* 定義在 limit.h中 */

int main(int argc, char* argv[])
{
	int fd;
	char buff[MAX_BUFFER_SIZE];
	int nread;
	
	/* Judge whether the fifo is existed */	
	if(access(MYFIFO, F_OK) == -1)
	{
		if((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST))
		{
			printf("Cannot create fifo file\n");
		}
	}

	/* Open the fifo in the blocked way */
	fd = open(MYFIFO, O_RDONLY);
	if(fd == -1)
	{
		printf("Open fifo file error\n");
		exit(1);
	}
	while(1)
	{
		memset(buff, 0, sizeof(buff));
		/* read string from named pipe */
		if((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0)
		{
			printf("Read '%s' to FIFO\n", buff);
		}
	}
	close(fd);	
	exit(0);
}

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>

#define MYFIFO "/tmp/myfifo"	/* 有名管道檔名*/
#define MAX_BUFFER_SIZE PIPE_BUF /* 定義在 limits.h中 */

int main(int argc, char* argv[])
{
	int fd;
	char buff[MAX_BUFFER_SIZE];
	int nwrite;
	
	if(argc <= 1)
	{
		printf("Usage: ./fifo_write string\n");
		exit(1);
	}
	sscanf(argv[1], "%s", buff);

	fd = open(MYFIFO, O_WRONLY);
	if(fd == -1)
	{
		printf("Open fifo file error\n");
		exit(1);
	}
	
	/* Write string to named pipe */
	if((nwrite = write(fd, buff, MAX_BUFFER_SIZE)) > 0)
	{
		printf("Write '%s' to FIFO\n", buff);
	}
	close(fd);
	
	exit(0);
}

2、訊號(Signal)

訊號是在軟體層次上對中斷機制的一種模擬,它是一種比較複雜的通訊方式,用於通知程序有某事件發生;一個程序收到一個訊號與處理器收到一個終端請求的效果是一樣的。訊號是非同步的,一個程序不必通過任何操作等待訊號的到達,程序也不知道訊號什麼時候到達。訊號可以直接進行使用者程序和核心程序之間的互動,核心程序亦可利用訊號來通知使用者程序發生了哪些系統事件。訊號是程序間通訊機制中唯一的非同步通訊機制,可以看作非同步通知,用於通知接收訊號的程序有哪些事件發生了。 訊號的生命週期包括三個階段:訊號產生、訊號在程序中註冊和執行訊號處理函式、訊號在程序中登出。其中訊號的產生、註冊、登出是訊號內部實現機制而不是訊號的函式實現。 訊號的處理包括訊號的傳送、捕捉及訊號的處理。其各自對應的函式如下:
  • 傳送訊號的函式:kill()   raise()
  • 捕捉訊號的函式:alarm()  pause()
  • 處理訊號的函式:sigal() sigaction()
訊號事件發生來源:硬體來源(按鍵和硬體故障)、軟體來源(傳送訊號的函式及非法運算操作等) 程序響應訊號的三種方式:
  1. 忽略訊號,但不包括SIGKILL、SIGSTOP。
  2. 捕捉訊號, 定義訊號處理函式,當訊號事件發生時,執行相應的訊號處理函式。
  3. 執行預設操作。

3、訊息佇列(Message Quene)

訊息佇列是訊息的連結表,包括Posix訊息佇列和System V訊息佇列。它克服了管道和訊號量通訊方式中資訊量有限的缺點,具有寫許可權的程序可以按照一定的規則向訊息佇列中新增新資訊;具有訊息佇列讀許可權的程序可以從訊息佇列中讀取訊息。

4、共享記憶體(Shared Memory)

最有效的程序間通訊方式,多個程序可以訪問同一塊記憶體空間,不同的程序可以看到對方程序中對共享記憶體中資料的更新。
note: 這種通訊方式需要某種同步機制, 如互斥鎖和訊號量等。

5、訊號量(Semaphore)

在多工作業系統環境下,多個程序會同時執行,程序間會有可能協同完成同一個任務或者爭奪系統資源進入競爭狀態,即程序間的同步和互斥關係;訊號量的出現主要作為程序之間及統一程序中不同執行緒之間的同步和互斥手段。它包括一個稱為訊號量的變數和在該訊號量下等待資源的程序等待佇列,以及對訊號量進行的兩個原子操作(PV操作)。
PV原子操作定義如下:
P操作: 如果有可用的資源(訊號量值 > 0),則佔用一個資源(給訊號量值減1,進入臨界區程式碼);如果沒有可用的資源(訊號量值=0),則被阻塞直到系統將資源分配給該程序(進入等待佇列,一直等到資源輪到該程序);
V操作: 如果在該訊號量的等待佇列中有程序在等待資源,則喚醒一個阻塞程序;如果沒有程序等待它,則釋放一個資源(給訊號量值加1);
使用訊號量訪問臨界區的常用虛擬碼如下:
{
/* 設R為某種資源,S為某種資源的訊號量 */
INIT_VAL(S);           /* 對訊號量S進行初始化 */
非臨界區;
P(S);                  /* 進行P操作 */
臨界區(使用資源R)    /* 只有有限個程序被允許進入該區 */
V(S);                  /* 進行V操作 */
非臨界區;
}
使用訊號量的基本步驟及涉及的函式:
建立訊號量及獲得在系統中已經存在的訊號量,不同程序可以通過使用同一個訊號量鍵值來獲得同一個訊號量 —— 函式semget();
初始化訊號量(二維訊號量一般初始化為1) —— 函式semctl()中的SETVAL操作;
進行訊號量的PV操作,實現程序間同步和互斥的核心工作部分 —— 函式semop();
如果不需要訊號量,則從系統中刪除掉它(已刪除的訊號不可在程式中再次操作) —— 函式setctl()中IPC_RMID;

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <fcntl.h>
union semun {
int val;/* Value for SETVAL */
struct semid_ds *buf;   /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array;  /* Array for GETALL, SETALL */
struct seminfo *__buf;  /* Buffer for IPC_INFO Linux-specific */ 
};

/* Function:Initialze the semaphore */
int init_sem(int sem_id, int init_value)
{
        union semun sem_union;
        sem_union.val = init_value;
        if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
        {
                perror("Initialize semaphore");
                return -1;
        }
        return 0;
}


/* Function:Delete the semaphore from system */
int del_sem(int sem_id)
{
        union semun sem_union;
        if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
        {
                perror("Delete semaphore");
                return -1;
        }
}


/* Function: P operation */
int sem_p(int sem_id)
{
        struct sembuf sem_b;
        sem_b.sem_num = 0;      /* Single semaphore should be set with 0 */
        sem_b.sem_op = -1;      /* P operation */
        sem_b.sem_flg = SEM_UNDO; /* Auto free semaphore that has left in system */
        if(semop(sem_id, &sem_b, 1) == -1)
        {
                perror("P operation");
                return -1;
        }
        return 0;
}


/* Function: V operation */
int sem_v(int sem_id)
{
        struct sembuf sem_b;
        sem_b.sem_num = 0;      /* Single semaphore should be set with 0 */
        sem_b.sem_op = 1;      /* V operation */
        sem_b.sem_flg = SEM_UNDO; /* Auto free semaphore that has left in system */
        if(semop(sem_id, &sem_b, 1) == -1)
        {
                perror("V operation");
                return -1;
        }
        return 0;
}
利用訊號量控制程序同步的例項程式—— sem_fork.c:
說明:
訊號量操作增加之前程序執行順序:父程序 — 子程序
訊號量操作增加之後程序執行順序:子程序 — 父程序
#include "sem_com.h"

#define DELAY_TIME 3

int main()
{
	pid_t result;
	int sem_id;
	
	sem_id = semget(ftok(".", 'a'), 1, 0666|IPC_CREAT);
	init_sem(sem_id, 0);
	
	/* Call the fork() */
	result = fork();
	if(result == -1)
	{
		perror("fork()");
	}
	else if(result == 0)
	{
		printf("Child process will wait for some seconds...\n");
		sleep(DELAY_TIME);
		printf("The returned value is %d in the child process(PID = %d)\n", result, getpid());
	
	sem_v(sem_id);
	}
	else
	{
		sem_p(sem_id);
		printf("The returned value is %d in the father process(PID = %d)\n",result, getpid());
	
	sem_v(sem_id);
	del_sem(sem_id);
	}
	exit(0);
}


6、套接字(Socket)

應用非常廣泛的一種程序間通訊機制,可以用於網路中不同機器之間的程序間通訊。

相關推薦

Linux程序常用通訊方式

1、無名管道(Pipe)及有名管道(Named Pipe) ——管道是Linux中基於檔案描述符的程序間通訊方式之一,它把一個程式的輸出直接連線到另一個程式的輸入。 無名管道:用於具有親緣關係程序間的通訊。  (不常用) 特點: 僅用於父子或者兄弟程序之間通訊半雙工通訊

Linux程序通訊機制----訊息佇列

一、什麼是訊息 訊息(message)是一個格式化的可變長的資訊單元。訊息機制允許由一個程序給其它任意的程序傳送一個訊息。當一個程序收到多個訊息時,可將它們排成一個訊息佇列。 1、訊息機制的資料結構 (1)訊息首部 記錄一些與訊息有關的資訊,如訊息的型別、大小、

(轉)LinuxSSH遠程訪問控制

體系 字符 配置文件 art 文件 優先 class 遠程訪問 安全 詳解Linux中SSH遠程訪問控制 原文:http://blog.51cto.com/dengqi/1260038 SSH:是一種安全通道協議,主要用來實現字符界面的遠程登錄,遠程復制等功能(使用TCP的

linux進程通信-信號

前言 prime 退出 pause 其余 type 客戶端 arm 進程間通信   前言:之前說看《C++ Primer 》暫時擱淺一下,迷上公司大神寫的代碼,想要明白,主要是socket、進程間通信!   知道進程間通信:信號、信號量、管道、消息隊列、共享內存(共享存儲)

VC++程序相互通訊的十一種方法

 程序通常被定義為一個正在執行的程式的例項,它由兩個部分組成:  一個是作業系統用來管理程序的核心物件。核心物件也是系統用來存放關於程序的統計資訊的地方  另一個是地址空間,它包含所有的可執行模組或DLL模組的程式碼和資料。它還包含動態分配的空間。如執行緒堆疊和堆分配空間。每

Linux程序通訊方式和原理【轉】

程序的概念 程序是作業系統的概念,每當我們執行一個程式時,對於作業系統來講就建立了一個程序,在這個過程中,伴隨著資源的分配和釋放。可以認為程序是一個程式的一次執行過程。 程序通訊的概念 程序使用者空間是相互獨立的,一般而言是不能相互訪問的。但很多情況下程序間需要互相通

Linux程序通訊

程序間通訊就是在不同程序之間傳播或交換資訊。但是,我們知道程序是具有獨立性的,因此,程序之間不可能直接進行通訊。人們之間交流需要空氣作為介質,程序之間“交流”也需要一個媒介,那麼程序之間存在著什麼雙方都可以訪問的介質呢? 程序的使用者空間是互相獨立的,一般而言是不能互相訪問的,唯一的例

linux kill命令引數及用法--linux終止程序命令

Linux kill 命令使用詳解 功能說明:刪除執行中的程式或工作。 語  法:kill [-s <資訊名稱或編號>][程式] 或 kill [-l <資訊編號>] 補充說明:kill可將指定的資訊送至程式。預設的資訊為SIGTERM(15),可

Linux程序通訊方式和原理

程序的概念 程序是作業系統的概念,每當我們執行一個程式時,對於作業系統來講就建立了一個程序,在這個過程中,伴隨著資源的分配和釋放。可以認為程序是一個程式的一次執行過程。 程序通訊的概念 程序使用者空間是相互獨立的,一般而言是不能相互訪問的。但很多

linux、windows下的程序通訊方式、執行緒通訊方式

Linux程序間的通訊方式:管道、有名管道、訊號量、訊息佇列、共享記憶體、訊號、socket Windows程序間的通訊方式:管道、訊號量、訊息佇列、共享記憶體、socket Linxu執行緒間的通訊方式:互斥量、條件變數、訊號量、訊號 Windows執行

命令列瀏覽器 curl 命令,Linux訪問url地址

http://hi.baidu.com/oyvfhp/item/747ecf16e4619c3ab83180ffCURL --- 命令列瀏覽器這東西現在已經是蘋果機上內建的命令列工具之一了,可見其魅力之一斑1)二話不說,先從這裡開始吧!curl http://www.yaho

Linux核心程序排程函式schedule()的觸發和執行時機

核心的排程操作分為觸發和執行兩個部分,觸發時僅僅設定一下當前程序的TIF_NEED_RESCHED標誌,執行的時候則是通過schedule()函式來完成程序的選擇和切換。當前程序的thread_info->flags中TIF_NEED_RESCHED位表示需要呼叫schedule()函式進行排程。核心在

程序通訊方式總結

程序通訊,是指程序之間的資訊交換 具體通訊方法有以下8種: (一)低階程序通訊 1. 訊號量 適用場景:在程序互斥中,程序通過只修改訊號量來想其他程序表明臨界資源是否可用。 缺點:1)效率低,生產者每

JAVA程序通訊方式(IPC)

JAVA程序間通訊的方法主要有以下幾種:  (1)管道(Pipe):管道可用於具有親緣關係程序間的通訊,允許一個程序和另一個與它有共同祖先的程序之間進行通訊。  (2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,除具有管道所具有的功能外,它還允許無親

1、幾種程序通訊方式

# 管道( pipe ):管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的程序間使用。程序的親緣關係通常是指父子程序關係。 # 有名管道 (named pipe) : 有名管道也是半雙工的通訊方式,但是它允許無親緣關係程序間的通訊。 # 訊號量( semophore ) : 訊號量是

程序資料通訊方式和特點

由於不同的程序執行在各自不同的記憶體空間中.一方對於變數的修改另一方是無法感知的.因此.程序之間的資訊傳遞不可能通過變數或其它資料結構直接進行,只能通過程序間通訊來完成。 根據程序通訊時資訊量大小的不同,可以將程序通訊劃分為兩大型別:控制資訊的通訊和大批資料資訊的通訊.前者

Windows程序各種通訊方式淺談

1 Windows程序間通訊的各種方法 程序是裝入記憶體並準備執行的程式,每個程序都有私有的虛擬地址空間,由程式碼、資料以及它可利用的系統資源(如檔案、管道等)組成。 多程序/多執行緒是Windows作業系統的一個基本特徵。Microsoft Win32應用程式設計介面(

程序通訊方式_訊息佇列

訊息佇列:提供了一種從一個程序向另一個程序傳送一個數據塊的方法,而且每個資料塊都被認為含有一個型別,接收程序可以獨立地接受含有不同型別值得資料塊。        訊息:資料 & 型別        佇列:一種資料結構,先進先出        訊息佇列:是一種臨時儲存

python程序通訊方式--------管道

管道    先畫一幅圖幫助大家理解下管道的基本原理            現有2個程序A和B,他們都在記憶體中開闢了空間,那麼我們在記憶體中再開闢一個空間C,作用是連線這兩個程序的。對於程序來說記憶體空間是可以共享的(任何一個程序都可以使用記憶體,記憶體當中的空間是用地址來標

Java面試--程序通訊方式

面試題:程序間的通訊方式(VIVO、阿里巴巴面試題) 面試題:程序通訊方式有哪些,問我分別怎麼使用,管道有哪些型別,各有什麼優缺點。(百度面試題) 一、程序通訊的目的 1、資料傳輸