概念 Linux本地IPC之Unix域協議

2021-09-24 02:57:33 字數 4062 閱讀 9387

unix域協議並不是乙個實際的協議族,它只是在同一臺主機上進行客戶-伺服器通訊時,使用與在不同主機上的客戶和伺服器間通訊時相同的api(套介面或xti)的一種方法,我們知道不同主機之間的tcp或者udp通訊其實也是通過socket來實現的。

當客戶和伺服器在同一臺主機上時,unix域協議是ipc通訊方式的一種替代品。也就是說unix域協議是程序間通訊(ipc)的一種方法,還可以通過管道等等。

unix域提供了兩種型別的套介面:位元組流套介面(與tcp類似)和資料報套介面(與udp類似)。

unix domain socket 或者 ipc socket (程序間通訊 socket)是一種終端,可以使同一臺作業系統上的兩個或多個程序進行資料通訊。與管道相比,unix domain sockets 既可以使用位元組流,又可以使用資料佇列,而管道通訊則只能使用位元組流。unix domain sockets的介面和internet socket很像,但它不使用網路底層協議來通訊。unix domain socket 的功能是posix作業系統裡的一種元件。 

unix domain sockets 使用系統檔案的位址來作為自己的身份。它可以被系統程序引用。所以兩個程序可以同時開啟乙個unix domain sockets來進行通訊。不過這種通訊方式是發生在系統核心裡而不會在網路裡傳播。

unix domain socket ipc

兩種api介面,類似於網路socket的tcp和udp,但是面向訊息的unix domain socket也是可靠的,訊息既不會丟失也不會順序錯亂。

unix domain socket是全雙工的,api介面語義豐富,相比其它ipc機制有明顯的優越性,目前已成為使用最廣泛的ipc機制,比如x window伺服器和gui程式之間就是通過unix domain socket通訊的。

使用unix domain socket的過程和網路socket十分相似,也要先呼叫socket()建立乙個socket檔案描述符,address family指定為af_unix,type可以選擇sock_dgram或sock_stream,protocol引數仍然指定為0即可。

unix domain socket與網路socket程式設計最明顯的不同在於位址格式不同,用結構體sockaddr_un表示網路程式設計的socket位址是ip位址加埠號,而unix domain socket的位址是乙個socket型別的檔案在檔案系統中的路徑,這個socket檔案由bind()呼叫建立,如果呼叫bind()時該檔案已存在,則bind()錯誤返回。

以下程式將unix domain socket繫結到乙個位址。

#include #include #include #include #include int main(void)

size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);

if (bind(fd, (struct sockaddr *)&un, size) < 0)

printf("unix domain socket bound\n");

exit(0);

}

注意程式中的offsetof巨集,它在stddef.h標頭檔案中定義:

#define offsetof(type, member) ((int)&((type *)0)->member)
offsetof(struct sockaddr_un, sun_path)就是取sockaddr_un結構體的sun_path成員在結構體中的偏移,也就是從結構體的第幾個位元組開始是sun_path成員。想一想,這個巨集是如何實現這一功能的?

該程式的執行結果如下。

$ ./a.out

unix domain socket bound

$ ls -l foo.socket

srwxrwxr-x 1 user 0 aug 22 12:43 foo.socket

$ ./a.out

bind error: address already in use

$ rm foo.socket

$ ./a.out

unix domain socket bound

以下是伺服器的listen模組,與網路socket程式設計類似,在bind之後要listen,表示通過bind的位址(也就是socket檔案)提供服務。

#include #include #include #include #define qlen 10

/* * create a server endpoint of a connection.

* returns fd if all ok, <0 on error.

*/int serv_listen(const char *name)

if (listen(fd, qlen) < 0)

return(fd);

errout:

err = errno;

close(fd);

errno = err;

return(rval);

}

以下是伺服器的accept模組,通過accept得到客戶端位址也應該是乙個socket檔案,如果不是socket檔案就返回錯誤碼,如果是socket檔案,在建立連線後這個檔案就沒有用了,呼叫unlink把它刪掉,通過傳出引數uidptr返回客戶端程式的user id。

#include #include #include #include #include int serv_accept(int listenfd, uid_t *uidptr)

if (s_issock(statbuf.st_mode) == 0)

if (uidptr != null)

*uidptr = statbuf.st_uid; /* return uid of caller */

unlink(un.sun_path); /* we're done with pathname now */

return(clifd);

errout:

err = errno;

close(clifd);

errno = err;

return(rval);

}

以下是客戶端的connect模組,與網路socket程式設計不同的是,unix domain socket客戶端一般要顯式呼叫bind函式,而不依賴系統自動分配的位址。客戶端bind乙個自己指定的socket檔名的好處是,該檔名可以包含客戶端的pid以便伺服器區分不同的客戶端。

#include #include #include #include #include #include #define cli_path    "/var/tmp/"      /* +5 for pid = 14 chars */

/* * create a client endpoint and connect to a server.

* returns fd if all ok, <0 on error.

*/int cli_conn(const char *name)

/* fill socket address structure with server's address */

memset(&un, 0, sizeof(un));

un.sun_family = af_unix;

strcpy(un.sun_path, name);

len = offsetof(struct sockaddr_un, sun_path) + strlen(name);

if (connect(fd, (struct sockaddr *)&un, len) < 0)

return(fd);

errout:

err = errno;

close(fd);

errno = err;

return(rval);

}

Linux 程序間通訊之訊息佇列(IPC資源)

訊息佇列提供的服務就是乙個程序向乙個程序傳送有型別資料塊。訊息佇列提供了 個從 個程序向另外 個程序傳送 塊資料的 法每個資料塊都被認為是有 個型別,接收者程序接收的資料塊可以有不同的型別值訊息佇列也有管道 樣的不 就是每個訊息的最 度是有上限的 msgmax 每個訊息佇列的總的位元組數是有上限的 ...

Linux學習筆記之IPC 物件之訊號量集

目的 配合共享記憶體完成程序間通訊 使用框架 key 申請訊號量集 pv操作 解除安裝刪除訊號量集 semget semop semctl 1 申請訊號量 include int semget key t key,int nsems,int sem 功能 該函式可以使用特定的key向核心提出訊號量集...

Linux之執行緒概念(pthread)

執行緒概念 1 輕量級的程序,乙個程序內部可以有多個執行緒,預設情況下乙個程序只有乙個執行緒。2 執行緒是最小的執行單元,程序是最小的系統資源分配單位。3 核心實現都是通過clone函式實現,執行緒也有自己的pcb。檢視pthread庫版本命令 getconf gnu libpthread vers...