Linux Socket IPC

    Socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于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()错误返回。

服务端程序为

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/socket.h>
 4 #include <sys/un.h>
 5 #include <stddef.h>
 6 #include <unistd.h>
 7 
 8 int bindSocket(char* servname)
 9 {
10     struct sockaddr_un usock;
11     int ufd;
12     memset(&usock, 0, sizeof(usock));
13     usock.sun_family = AF_UNIX;
14     strcpy(usock.sun_path, servname);
15     if((ufd = socket(AF_UNIX, SOCK_STREAM,0)) < 0)
16     {
17         perror("socket() error!");
18         exit(-1);
19     }
20     int len = offsetof(struct sockaddr_un, sun_path) + strlen(usock.sun_path);
21     if(bind(ufd, (struct sockaddr*)&usock, len) < 0)
22     {
23         perror("bind() error!");
24         exit(-1);
25     }
26 
27     return ufd;
28 }
29 int acceptSocket(int ssock,struct sockaddr_un *un)
30 {
31 
32     int csock, len;
33 
34     len = sizeof(struct sockaddr_un); //这句话必须有,因为len是传入传出参数,在传入时如果没有指定大小,有可能传入上次传出参数值。
35     if((csock = accept(ssock, (struct sockaddr*)un, (socklen_t*)&len)) < 0)
36     {
37         perror("accept() error!");
38         exit(-1);
39     }
40     len -= offsetof(struct sockaddr_un, sun_path);
41 //    un->sun_path[len] = 0;
42     printf("client file:[%s]\n", un->sun_path);
43     return csock;
44 
45 }
46 
47 int main(void)
48 {
49     char servName[20];
50     sprintf(servName,"server");
51     int sfd = bindSocket(servName);
52     if(listen(sfd, 5) < 0)
53     {
54         perror("listen() error!");
55         exit(-1);
56     }
57     struct sockaddr_un un;
58     int cfd = acceptSocket(sfd, &un);
59     char buf[100];
60     int s = read(cfd, buf, sizeof(buf));
61     write(STDOUT_FILENO,buf,s);
62 }

客户端代码如下:

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <string.h>
 6 #include <sys/un.h>
 7 #include <stddef.h>
 8 
 9 int cli_connect(const char *name)
10 {
11     int len;
12     struct sockaddr_un un;
13     memset(&un,0,sizeof(un));
14     un.sun_family = AF_UNIX;
15     sprintf(un.sun_path,"client%05d",getpid());
16     int cfd;
17     if((cfd = socket(AF_UNIX,SOCK_STREAM,0)) < 0)
18     {
19         perror("socket() error");
20         exit(-1);
21     }
22     len = offsetof(struct sockaddr_un,sun_path) + strlen(un.sun_path);
23     if(bind(cfd,(struct sockaddr*)&un,len) < 0)
24     {
25         perror("bind() error");
26         exit(-1);
27     }
28     printf("client path=%s\n", un.sun_path);
29     memset(&un,0,sizeof(un));
30     un.sun_family = AF_UNIX;
31     sprintf(un.sun_path, name);
32     len = offsetof(struct sockaddr_un,sun_path);
33     len += strlen(un.sun_path);
34     printf("sunpath=%s\n",un.sun_path);   
35  if(connect(cfd,(struct sockaddr*)&un,len) < 0)
36     {
37         perror("connect() error");
38         exit(-1);
39     }
40     return cfd;
41 }
42 
43 int main(void)
44 {
45     int cfd = cli_connect("server");
46     char *buf = "hello world! ooooo";
47     if(write(cfd,buf,strlen(buf)) < 0)
48         perror("error");
49     return cfd;
50 }

 

posted on 2013-09-16 10:59  cfox  阅读(466)  评论(0编辑  收藏  举报

导航