一。Unix domain socket概念服務器
socket API本來是爲網絡通信設計的,但後來在socket的框架上發展出一種IPC機制,就是UNIX Domain Socket。雖然網絡socket也可用於同一臺主機的進程間通信(經過loopback地址127.0.0.1),可是UNIX Domain Socket用於IPC更有效率:不須要通過網絡協議棧,不須要打包拆包、計算校驗和、維護序號和應答等,只是將應用層數據從一個進程拷貝到另外一個進程。這是由於,IPC機制本質上是可靠的通信,而網絡協議是爲不可靠的通信設計的。網絡
UNIX Domain Socket是全雙工的,API接口語義豐富,相比其它IPC機制有明顯的優越性,目前已成爲使用最普遍的IPC機制,好比X Window服務器和GUI程序之間就是經過UNIXDomain Socket通信的。框架
二。本地套接字地址結構dom
struct sockaddr_un {socket
__kernel_sa_family_t sun_family; /* AF_UNIX */ 地址結構類型oop
char sun_path[UNIX_PATH_MAX]; /* pathname */ socket文件名(含路徑)spa
};設計
三。代碼示例code
服務端server
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/socket.h> 4 #include <strings.h> 5 #include <string.h> 6 #include <ctype.h> 7 #include <arpa/inet.h> 8 #include <sys/un.h> 9 #include <stddef.h> 10 11 #include "wrap.h" 12 13 #define SERV_ADDR "serv.socket" 14 15 int main(void) 16 { 17 int lfd, cfd, len, size, i; 18 struct sockaddr_un servaddr, cliaddr; 19 char buf[4096]; 20 21 lfd = socket(AF_UNIX, SOCK_STREAM, 0); //本地套接字 AF_UNIX 22 23 bzero(&servaddr, sizeof(servaddr)); 24 servaddr.sun_family = AF_UNIX; //初始化地址信息 25 strcpy(servaddr.sun_path,SERV_ADDR); //套接字文件名 26 27 len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path); /* servaddr total len */ 28 //offsetof計算結構體中成員的偏移量,偏移量+文件名大小=結構體長度 29 30 31 unlink(SERV_ADDR); /* 確保bind以前serv.sock文件不存在,bind會建立該文件 */ 32 bind(lfd, (struct sockaddr *)&servaddr, len); /* 參3不能是sizeof(servaddr) */ 33 34 listen(lfd, 20); 35 36 printf("Accept ...\n"); 37 while (1) { 38 len = sizeof(cliaddr); 39 cfd = accept(lfd, (struct sockaddr *)&cliaddr, (socklen_t *)&len); 40 41 len -= offsetof(struct sockaddr_un, sun_path); /* 獲得文件名的長度 */ 42 cliaddr.sun_path[len] = '\0'; /* 確保打印時,沒有亂碼出現 */ 43 44 printf("client bind filename %s\n", cliaddr.sun_path); 45 46 while ((size = read(cfd, buf, sizeof(buf))) > 0) { 47 for (i = 0; i < size; i++) 48 buf[i] = toupper(buf[i]); 49 write(cfd, buf, size); 50 } 51 close(cfd); 52 } 53 close(lfd); 54 55 return 0; 56 }
客戶端
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <strings.h> #include <string.h> #include <ctype.h> #include <arpa/inet.h> #include <sys/un.h> #include <stddef.h> #include "wrap.h" #define SERV_ADDR "serv.socket" #define CLIE_ADDR "clie.socket" int main(void) { int cfd, len; struct sockaddr_un servaddr, cliaddr; char buf[4096]; cfd = socket(AF_UNIX, SOCK_STREAM, 0); bzero(&cliaddr, sizeof(cliaddr)); cliaddr.sun_family = AF_UNIX; strcpy(cliaddr.sun_path,CLIE_ADDR); len = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path); /*計算客戶端地址結構有效長度 */ unlink(CLIE_ADDR); bind(cfd, (struct sockaddr *)&cliaddr, len); /* 客戶端也須要bind, 不能依賴自動綁定*/ bzero(&servaddr, sizeof(servaddr)); /* 構造server 地址 */ servaddr.sun_family = AF_UNIX; strcpy(servaddr.sun_path,SERV_ADDR); len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path); /* 計算服務器端地址結構有效長度 */ connect(cfd, (struct sockaddr *)&servaddr, len); while (fgets(buf, sizeof(buf), stdin) != NULL) { write(cfd, buf, strlen(buf)); len = read(cfd, buf, sizeof(buf)); write(STDOUT_FILENO, buf, len); } close(cfd); return 0; }