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通信的。框架

二。本地套接字地址結構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;
}
相關文章
相關標籤/搜索