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

时间: 2024-12-21 17:23:58

socket IPC(本地套接字 domain)的相关文章

【转】PHP实现系统编程(四)--- 本地套接字(Unix Domain Socket)

原文:http://blog.csdn.net/zhang197093/article/details/78143687?locationNum=6&fps=1 -------------------------------------------------------------------------------------------------------------------------------------------------------- Socket API一开始是为了

Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字 . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录 (四) 一起学 Unix 环境高级编程 (APUE) 之 系统数据文件和信息 (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境 (六) 一起学 Unix 环境高级编程 (APU

(十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录 (四) 一起学 Unix 环境高级编程 (APUE) 之 系统数据文件和信息 (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境 (六) 一起学 Unix 环境高级编程 (APUE) 之 进程控制 (七) 一起学 Unix 环境高级编程 (APUE)

Linux 进程间通信(二)(网络IPC:套接字)

socket描述符 套接字是通信端点的抽象,创建一个套接字使用如下函数: #include <sys/socket.h> int socket(int domain, int type, int protocol); 返回值:若成功,返回套接字描述符:若出错,返回-1 说明: domain: 指定通信的特征,包括地址格式,以AF_开头的常数表示地址族(address family): 域 说明 AF_INET IPv4因特网域 AF_INET6 IPv6因特网域 AF_UNIX UNIX域 A

IPC——流套接字通信

Linux进程间通信——使用流套接字 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编程,这里将会简单地讲述如何使用socket进行简单的网络编程. 一.什么是socket socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行.也就是说它可以让不在同一台计算机

IPC——数据报套接字通信

Linux进程间通信——使用数据报套接字 前一篇文章,Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接字的使用. 一.简单回顾——什么是数据报套接字 socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行.也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信.也因为这样,套接字明确地将客户端和服务器

socket模块(套接字模块)

socket模块(套接字模块) 一.最简单版本(互传一次就结束) # 客户端 import socket client = socket.socket() client.connect(('127.0.0.1', 8080)) # 8080是端口号 ''' 来源百度百科 '127.0.0.1'是本机回还地址,不属于任何一个有类别地址类.它代表设备的本地虚拟接口,所以默认被看作是永远不会宕掉的接口.在Windows操作系统中也有相似的定义,所以通常在安装网卡前就可以ping通这个本地回环地址.一般

第16章 网络IPC:套接字总结

1 套接字是通信端点的抽象 创建套接字: int socket(int domain,int type,int protocol) domain:通信域 AF_INET.AF_INET6.AF_LOCAL.AF_UNSPEC type:套接字类型,SOCK_DGRAM.SOCK_STREAM.SOCK_SEQPACKET.SOCK_RAW protocol:通常为0,表示domain和type默认的协议 linux中套接字使用文件描述符实现的,文件描述符上使用的大多数函数可以用于套接字 套接字输

IPC之套接字

IPC(Inter-Process Communication,进程间通信)实现方式 1)管道: - 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程之间使用(进程的亲缘关系通常是指父子进程关系) 2)有名管道(FIFO): - 有名管道也是半双工的通信方式,但是允许在没有亲缘关系的进程之间使用,管道是先进先出的通信方式 3)信号量: - 信号量是一个计数器,可以用来控制多个进程对共享资源的访问 - 它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源