IPC-本地套接字

一。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通讯的。

二。本地套接字地址结构

struct sockaddr_un {

__kernel_sa_family_t sun_family;                  /* AF_UNIX */                  地址结构类型

char sun_path[UNIX_PATH_MAX];                 /* pathname */                socket文件名(含路径)

};

三。代码示例

服务端

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

 

posted @ 2019-08-07 14:48  荼离伤花  阅读(350)  评论(0编辑  收藏  举报