• 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]
    ", 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
    ", 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
    ",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 }
  • 相关阅读:
    慕课网-安卓工程师初养成-3-2 Java中的算术运算符
    慕课网-安卓工程师初养成-3-1 什么是运算符
    慕课网-安卓工程师初养成-2-13 练习题
    慕课网-安卓工程师初养成-2-12 如何在Java中使用注释
    慕课网-安卓工程师初养成-2-11 Java常量
    慕课网-安卓工程师初养成-2-10 Java中的强制类型转换
    试把一个正整数n拆分为若干个
    求解两个给定正整数m、n的最大公约数(m、n)
    统计n!尾部零
    横竖折对称方阵
  • 原文地址:https://www.cnblogs.com/cfox/p/3323873.html
Copyright © 2020-2023  润新知