• socket IPC(本地套接字 domain)


    1.简介

      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程序之间就是通过UNIXDomain Socket通讯的

    2.使用介绍

      使用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()错误返回。

    3.与网络套接字对比

      对比网络套接字地址结构和本地套接字地址结构:

      struct sockaddr_in {

      __kernel_sa_family_t sin_family;                             /* Address family */      地址结构类型

      __be16 sin_port;                                                 /* Port number */             端口号

      struct in_addr sin_addr;                                               /* Internet address */     IP地址

      };

      struct sockaddr_un {

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

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

      };

    4.代码实现案列

    文件1:wrap.h自己封装的出错处理函数头文件

     1 #ifndef __WRAP_H_
     2 #define __WRAP_H_
     3 
     4 void perr_exit(const char* s);
     5 int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr);
     6 int Bind(int fd,const struct sockaddr* sa,socklen_t salen);
     7 int Connect(int fd,const struct sockaddr* sa,socklen_t salen);
     8 int Listen(int fd,int backlog);
     9 int Socket(int family,int type,int protocol);
    10 ssize_t Read(int fd,void* ptr,size_t nbytes);
    11 ssize_t Write(int fd,const void* ptr,size_t nbytes);
    12 int Close(int fd);
    13 ssize_t Readn(int fd,void* vptr,size_t n);
    14 ssize_t Writen(int fd,const void* vptr,size_t n);
    15 ssize_t my_read(int fd,char* ptr);
    16 ssize_t Readline(int fd,void* vptr,size_t maxlen);
    17 
    18 #endif

    文件2:wrap.c自己封装的出错处理函数实现

      1 #include<stdlib.h>
      2 #include<stdio.h>
      3 #include<unistd.h>
      4 #include<errno.h>
      5 #include<sys/socket.h>
      6 
      7 void perr_exit(const char* s)
      8 {
      9     perror(s);
     10     exit(-1);
     11 }
     12 
     13 int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr)
     14 {
     15     int n;
     16 again:
     17     if((n = accept(fd,sa,salenptr))<0)
     18     {
     19         if((errno == ECONNABORTED)||(errno == EINTR))
     20         {
     21             goto again;
     22         }
     23         else
     24         {
     25             perr_exit("accept error");
     26         }
     27     }
     28     return n;
     29 }
     30 
     31 int Bind(int fd,const struct sockaddr* sa,socklen_t salen)
     32 {
     33     int n;
     34     if((n = bind(fd,sa,salen))<0)
     35     {
     36         perr_exit("bind error");
     37     }
     38     return n;
     39 }
     40 
     41 int Connect(int fd,const struct sockaddr* sa,socklen_t salen)
     42 {
     43     int n;
     44     n = connect(fd,sa,salen);
     45     if(n<0)
     46     {
     47         perr_exit("connect error");
     48     }
     49     return n;
     50 }
     51 
     52 int Listen(int fd,int backlog)
     53 {
     54     int n;
     55     if((n = listen(fd,backlog))<0)
     56     {
     57         perr_exit("listen error");
     58     }
     59     return n;
     60 }
     61 
     62 int Socket(int family,int type,int protocol)
     63 {
     64     int n;
     65     if((n = socket(family,type,protocol))<0)
     66     {
     67         perr_exit("socket error");
     68     }
     69     return n;
     70 }
     71 
     72 ssize_t Read(int fd,void* ptr,size_t nbytes)
     73 {
     74     ssize_t n;
     75 again:
     76     if((n = read(fd,ptr,nbytes)) == -1)
     77     {
     78         if(errno == EINTR)
     79         {
     80             goto again;
     81         }
     82         else
     83         {
     84             return -1;
     85         }
     86     }
     87     return n;
     88 }
     89 
     90 ssize_t Write(int fd,const void* ptr,size_t nbytes)
     91 {
     92     ssize_t n;
     93 again:
     94     if((n = write(fd,ptr,nbytes)) == -1)
     95     {
     96         if(errno == EINTR)
     97         {
     98             goto again;
     99         }
    100         else
    101         {
    102             return -1;
    103         }
    104     }
    105     return n;
    106 }
    107 
    108 int Close(int fd)
    109 {
    110     int n;
    111     if((n = close(fd)) == -1)
    112     {
    113         perr_exit("close error");
    114     }
    115     return n;
    116 }
    117 
    118 ssize_t Readn(int fd,void* vptr,size_t n)
    119 {
    120     size_t nleft;
    121     ssize_t nread;
    122     char *ptr;
    123     
    124     ptr = vptr;
    125     nleft = n;
    126 
    127     while(nleft > 0)
    128     {
    129         if((nread = read(fd,ptr,nleft))<0)
    130         {
    131             if(errno == EINTR)
    132             {
    133                 nread = 0;
    134             }
    135             else
    136             {
    137                 return -1;
    138             }
    139         }
    140         else if(nread == 0)
    141         {
    142             break;
    143         }
    144         nleft -= nread;
    145         ptr += nread;
    146     }
    147     return n-nleft;
    148 }
    149 
    150 ssize_t Writen(int fd,const void* vptr,size_t n)
    151 {
    152     size_t nleft;
    153     ssize_t nwritten;
    154     const char* ptr;
    155 
    156     ptr = vptr;
    157     nleft = n;
    158     while(nleft>0)
    159     {
    160         if((nwritten = write(fd,ptr,nleft))<=0)
    161         {
    162             if(nwritten < 0&& errno == EINTR)
    163             {
    164                 nwritten = 0;
    165             }
    166             else
    167             {
    168                 return -1;
    169             }
    170             nleft -= nwritten;
    171             ptr += nwritten;
    172         }
    173     }
    174     return n;
    175 }
    176 
    177 ssize_t my_read(int fd,char* ptr)
    178 {
    179     static int read_cnt;
    180     static char *read_ptr;
    181     static char read_buf[100];
    182 
    183     if (read_cnt <= 0) 
    184     {
    185 again:
    186         if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) 
    187         {
    188             if (errno == EINTR)
    189                 goto again;
    190             return -1;
    191         } else if (read_cnt == 0)
    192             return 0;
    193         read_ptr = read_buf;
    194     }
    195     read_cnt--;
    196     *ptr = *read_ptr++;
    197 
    198     return 1;
    199 }
    200 
    201 ssize_t Readline(int fd,void* vptr,size_t maxlen)
    202 {
    203     ssize_t n, rc;
    204     char    c, *ptr;
    205     ptr = vptr;
    206 
    207     for (n = 1; n < maxlen; n++) 
    208     {
    209         if ((rc = my_read(fd, &c)) == 1)
    210         {
    211             *ptr++ = c;
    212             if (c == '\n')
    213                 break;
    214         } else if (rc == 0) 
    215         {
    216             *ptr = 0;
    217             return n-1;                                                            
    218         } else                                            
    219             return -1;                                                
    220     }
    221     *ptr = 0;
    222 
    223     return n;
    224 }

    文件3:服务端程序server.c

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <sys/types.h>
     4 #include <sys/socket.h>
     5 #include <strings.h>
     6 #include <string.h>
     7 #include <ctype.h>
     8 #include <arpa/inet.h>
     9 #include<sys/un.h>
    10 #include<stdlib.h>
    11 #include<stddef.h>
    12 #include "wrap.h"
    13 #define SERV_ADDR "serv.socket"
    14 #define SERV_PORT 6666
    15 
    16 int main(void)
    17 {
    18     int lfd, cfd;
    19     int len, i;
    20     char buf[BUFSIZ];
    21 
    22     struct sockaddr_un serv_addr, clie_addr;
    23     socklen_t clie_addr_len;
    24 
    25     lfd = Socket(AF_UNIX, SOCK_STREAM, 0);
    26 
    27     unlink(SERV_ADDR);
    28     bzero(&serv_addr, sizeof(serv_addr));           
    29     serv_addr.sun_family = AF_UNIX;                 
    30     len=offsetof(struct sockaddr_un,sun_path)+strlen(SERV_ADDR);
    31     strcpy(serv_addr.sun_path,SERV_ADDR);
    32 
    33     Bind(lfd, (struct sockaddr *)&serv_addr, len);
    34 
    35     Listen(lfd, 128);                                
    36 
    37     printf("wait for client connect ...\n");
    38 
    39     clie_addr_len = sizeof(clie_addr_len);
    40 
    41     cfd = Accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
    42 
    43     while (1) {
    44         
    45         len = Read(cfd, buf, sizeof(buf));
    46         Write(STDOUT_FILENO, buf, len);
    47 
    48         for (i = 0; i < len; i++)
    49             buf[i] = toupper(buf[i]);
    50         Write(cfd, buf, len); 
    51     }
    52 
    53     Close(lfd);
    54     Close(cfd);
    55 
    56     return 0;
    57 }

    文件4:客户端程序client.c

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <string.h>
     4 #include <sys/socket.h>
     5 #include <arpa/inet.h>
     6 #include <stdlib.h>
     7 #include <stddef.h>
     8 #include <sys/un.h>
     9 #include <ctype.h>
    10 #include <sys/types.h>
    11 #include "wrap.h"
    12 #define CLIE_ADDR "clie.socket"
    13 #define SERV_ADDR "serv.socket"
    14 #define SERV_PORT 6666
    15 
    16 int main(void)
    17 {
    18     int lfd, len,n;
    19     struct sockaddr_un serv_addr, clie_addr;
    20     char buf[BUFSIZ]; 
    21 
    22     lfd = Socket(AF_UNIX, SOCK_STREAM, 0);
    23 
    24     bzero(&clie_addr, sizeof(clie_addr));                       
    25     clie_addr.sun_family = AF_UNIX;                                 
    26     strcpy(clie_addr.sun_path,CLIE_ADDR);
    27     len=offsetof(struct sockaddr_un,sun_path)+strlen(CLIE_ADDR);
    28     unlink(CLIE_ADDR);
    29     Bind(lfd,(struct sockaddr*)&clie_addr,len);
    30     
    31     bzero(&serv_addr,sizeof(serv_addr));
    32     serv_addr.sun_family=AF_UNIX;
    33     strcpy(serv_addr.sun_path,SERV_ADDR);
    34     len=offsetof(struct sockaddr_un,sun_path)+strlen(SERV_ADDR);
    35 
    36     Connect(lfd, (struct sockaddr *)&serv_addr, len);
    37 
    38     while (1) {
    39         fgets(buf, sizeof(buf), stdin);
    40         int r = Write(lfd, buf, strlen(buf));       
    41         printf("Write r ======== %d\n", r);
    42         n = Read(lfd, buf, sizeof(buf));
    43         printf("Read len ========= %d\n", n);
    44         Write(STDOUT_FILENO, buf, n);
    45     }
    46 
    47     Close(lfd);
    48 
    49     return 0;
    50 }

    文件5:makefile编译文件

     1 src = $(wildcard *.c)
     2 obj = $(patsubst %.c,%.o,$(src))
     3 
     4 all:server client
     5 server:server.o wrap.o
     6     gcc server.o wrap.o -o server -Wall
     7 client:client.o wrap.o
     8     gcc client.o wrap.o -o client -Wall
     9 %.o:%.c
    10     gcc -c $< -Wall
    11 .PHONY:clean all
    12 clean:
    13     -rm -rf server client $(obj)

    5.编译以及运行效果

    (1)执行make编译后如下图所示文件

    (2)先执行./server程序,再执行./client程序

    (3)在客户端输入hello world,会提示输入读写了多少字节,并且将服务端大写转小写写回到客户端屏幕上

    (4)程序执行完成后会在当前目录下观察到有两个套接字文件:clie.socket和serv.socket

    努力不一定有结果,有结果不一定是努力
  • 相关阅读:
    REVERSE!REVERSE!REVERSE!
    java和数据结构的面试考点
    39. recover rotated sorted array恢复旋转排序数组
    33. Search in Rotated Sorted Array旋转数组二分法查询
    搜索旋转排序数组 II
    Eclipse 查找
    在Java中返回多个值
    Java的标识符
    fwprintf (File input/output) – C 中文开发手册
    CSS盒子模型介绍 | CSS Box Model: Introduction to the CSS box model (Miscellaneous Level 1) – CSS 中文开发手册
  • 原文地址:https://www.cnblogs.com/liunianshiwei/p/6045303.html
Copyright © 2020-2023  润新知