一。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; }