《APUE》读书笔记-第十七章高级进程间通信

  本章主要介绍了基于STREAM的管道和UNIX域套接字,这些IPC可以在进程间传送打开文件描述符。服务进程可以使用它们的打开文件描述符与指定的名字相关联,客户进程可以使用这些名字与服务器进程通信。

1、基于STREAMS的管道

  STREAMS pipe是一个双向(全双工)管道,单个STREAMS管道就能向父、子进程提供双向的数据流。如下图所示:

下面采用STREAMS管道实现加法协同进程实例,程序如下:

View Code

 1  1 #include <stdio.h>
 2  2 #include <stdlib.h>
 3  3 #include <unistd.h>
 4  4 #include <errno.h>
 5  5 #include <string.h>
 6  6 #include <signal.h>
 7  7
 8  8 #define MAXLINE 1024
 9  9
10 10 static void sig_pipe(int signo)
11 11 {
12 12     printf("SIGPIPE caught\n");
13 13     exit(1);
14 14 }
15 15 int s_pipe(int fd[2])
16 16 {
17 17     return pipe(fd);
18 18 }
19 19 int main()
20 20 {
21 21     int     n;
22 22     int     fd[2];
23 23     pid_t   pid;
24 24     char    line[MAXLINE];
25 25
26 26     signal(SIGPIPE,sig_pipe);
27 27     s_pipe(fd);
28 28     if((pid = fork()) == -1)
29 29     {
30 30         perror("fork() error");
31 31         exit(-1);
32 32     }
33 33     if(pid == 0)  //子进程用fd[1]
34 34     {
35 35         close(fd[0]);
36 36         dup2(fd[1],STDIN_FILENO);
37 37         dup2(fd[1],STDOUT_FILENO);
38 38         execl(".//add","add",(char *)0);
39 39         exit(0);
40 40     }
41 41     else   //父进程用fd[0]
42 42     {
43 43         close(fd[1]);
44 44         while(fgets(line,MAXLINE,stdin) != NULL)
45 45         {
46 46             n = strlen(line);
47 47             if(write(fd[0],line,n) != n)
48 48             {
49 49                 perror("write() error to pipe");
50 50                 exit(-1);
51 51             }
52 52             if((n =read(fd[0],line,MAXLINE)) < 0)
53 53             {
54 54                 perror("read() error to pipe");
55 55                 exit(-1);
56 56             }
57 57             if(n==0)
58 58             {
59 59                 printf("child close pipe\n");
60 60                 break;
61 61             }
62 62             line[n] = '\0';
63 63             fputs(line,stdout);
64 64         }
65 65         exit(0);
66 66     }
67 67 }

 在APUE2 P469中这样讲:“solaris支持STREAMS管道,Linux的可选附加包也提供了STREAMS管道。”这个包没有安装上,程序不能正常运行。

1.2命名的STREAMS管道

  管道仅在相关进程之间使用,例如子进程集成父进程的管道。无关进程可以使用FIFO进行通信,但是这仅仅提供单向通信。STREAMS机制提供了一种有效的途径,使得进程可以给予管道一个文件系统的名字,避免了单向FIFO的问题。操作函数原型如下:

#include <stropts.h> 
int fattach(int fildes, const char *path);  //给STREAMS管道一个系统文件中的名字
int fdetach(const char *path); //撤销STREAMS管道文件与文件系统中名字的关联

2、UNIX域套接字

  UNIX域套接字用于在同一台机器上运行的进程之间的通信,UNIX域套接字仅仅复制数据,不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文。UNIX域套接字是套接字和管道之间的结合物,提供流和数据报两种接口。

UINX域套接字的好处:

(1)在同一台主机上进行通信时,是不同主机间通信的两倍

(2)UINX域套接口可以在同一台主机上,不同进程之间传递套接字描述符

(3)UINX域套接字可以向服务器提供客户的凭证(用户id或者用户组id)

UINX域套接字使用的地址通常是文件系统中一个文件路径,这些文件不是不同的文件,只能作为域套接字通信,不能读写。创建函数如下:

#include <sys/socket.h>
int socketpair(int domain, int type, int protocolint " sv [2]);

利用UNIX域实现全双工管道,程序如下:

View Code

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <errno.h>
 5 #include <string.h>
 6 #include <signal.h>
 7 #include <sys/socket.h>
 8 #define MAXLINE 1024
 9
10 static void sig_pipe(int signo)
11 {
12     printf("SIGPIPE caught\n");
13     exit(1);
14 }
15 int s_pipe(int fd[2])
16 {
17     return socketpair(AF_UNIX,SOCK_STREAM,0,fd);  //创建UNIX域套接字
18 }
19 int main()
20 {
21     int     n;
22     int     fd[2];
23     pid_t   pid;
24     char    line[MAXLINE];
25
26     signal(SIGPIPE,sig_pipe);
27     s_pipe(fd);
28     if((pid = fork()) == -1)
29     {
30         perror("fork() error");
31         exit(-1);
32     }
33     if(pid == 0)
34     {
35         close(fd[0]);
36         dup2(fd[1],STDIN_FILENO);
37         dup2(fd[1],STDOUT_FILENO);
38         execl(".//add","add",(char *)0);
39         exit(0);
40     }
41     else
42     {
43         close(fd[1]);
44         while(fgets(line,MAXLINE,stdin) != NULL)
45         {
46             n = strlen(line);
47             if(write(fd[0],line,n) != n)
48             {
49                 perror("write() error to pipe");
50                 exit(-1);
51             }
52             if((n =read(fd[0],line,MAXLINE)) < 0)
53             {
54                 perror("read() error to pipe");
55                 exit(-1);
56             }
57             if(n==0)
58             {
59                 printf("child close pipe\n");
60                 break;
61             }
62             line[n] = '\0';
63             fputs(line,stdout);
64         }
65         exit(0);
66     }
67 }

add是单独的程序,共程序调用,执行结果如下:

2.1命令UNIX域套接字

  UNIX域套接字的地址有sockaddr_run结构表示。

  #define UNIX_PATH_MAX 108
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname };

写个程序,将一个地址绑定一UNIX域套接字,程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stddef.h>
int main()
{
    int fd,size;
    struct sockaddr_un  un;
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path,"foo.socket");
    fd = socket(AF_UNIX,SOCK_STREAM,0);
    size = offsetof(struct sockaddr_un,sun_path) + strlen(un.sun_path);
    if(bind(fd,(struct sockaddr*)&un,size)<0)
    {
        perror("bind() error");
        exit(-1);
    }
    printf("UNIX domain socket bound\n");
    exit(0);
}

程序执行结果如下:

从结果可以看出,如果绑定地址时候,文件已经存在,那么bind请求将会失败,关闭套接字时,并不删除该文件。因此必须保证在应用程序终止前,对该文件进行解除链接操作。

2.2唯一连接

  服务器进程可以使用标准bind、listen和accept函数为客户进程安排一个唯一的UNIX域连接,客户进程使用connect与服务器进程联系,服务器进程接受了connect请求后,在服务器进程和客户进程之间就存在了唯一的连接。程序参考http://blog.csdn.net/youkuxiaobin/article/details/6965527 http://bbs.chinaunix.net/thread-2183106-1-1.html

 

 

时间: 2024-10-03 07:11:46

《APUE》读书笔记-第十七章高级进程间通信的相关文章

MYSQL必知必会读书笔记第三章之显示数据库_Mysql

MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. show column from tablename: 对每一个字段返回一行,行中包含字段名,数据类型.是否允许NULL.键信息.默认值以及其他信息. describe 语句: MySQL支持使用describ作为show columns from 的一种快捷方式.describ tablename 所支持的其他的show语句: show s

MYSQL必知必会读书笔记第六章之过滤数据_Mysql

mysql简介 MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. where子句的位置,在同时使用ORDER BY 和WHERE子句时应该让ORDER BY 位于where之后,否则会产生错误. 1.不匹配检查 复制代码 代码如下: SELECT vend_id FROM products where vend_id <>1003 等同于 复制代码 代码如下: SELECT vend_id

MYSQL必知必会读书笔记第四章之检索数据_Mysql

MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. 使用Select语句返回的数据,可能会发现显示的数据会与其他的地方顺序不同.出现这种情况很正常.如果没有明确排序查询结果.则返回的数据没有特殊意义.返回数据的顺序可能是是数据被添加到表中的顺序,也可能不是.只要返回相同数目的行,就是正常. 注意:SQL语句和大小写 请注意,SQL语句不区分大小写,因此select和SELECT是相同的.同样,

《APUE》读书笔记—第七章进程环境

本章主要介绍了Unix进程环境,包含main函数是如何被调用的,命令行参数如何传递,存储方式布局,分配存储空间,环境变量,进程终止方法,全局跳转longjmp和setjmp函数及进程的资源限制. main函数的原型为int main(int argc,char *argv[]);其中argc是命令行参数的数目,argv是指向参数的各个指针构成的数组.当内核执行C程序时,使用一个exec函数,在调用main函数前线调用一个特殊的启动例程,从内核获取命令行参数和环境变量. 进程终止分为正常终止和异常

《APUE》读书笔记—第四章文件和目录

本章主要介绍的是文件结构及目录.重点是通过stat函数获取文件的结构信息,然后是文件目录及其遍历.学完本章后,编写了一个输出给的目录下的文件信息的程序. 首先是包含在<sys/stat.h>文件下的stat.fstat.lstat三个函数,三个函数的原型如下: int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct 

《APUE》读书笔记—第三章文件I/O

Unix系统中大多数文件I/O只需用到五个函数:open.read.write.lseek.close.本章说介绍的I/O是不带缓冲的,即:每个read和write都调用内核中的一个系统调用.不是ISO C的组成部分.对于内核而言,所有打开的文件都通过文件描述符引用. 在<unistd.h>中定义三个标准的文件描述符: STDIN_FILENO 标准输入 STDOUT_FILENO 标准输出 STDERR_FILENO 标准出错输出 具体函数描述:在<fcntl.h>头文件下 in

《APUE》读书笔记—第五章标准I/O库

标准I/O库是ISO C的标准,在很多操作系统上面都实现.Unix文件I/O函数都是针对文件描述符的,当打开一个文件的时候,返回该文件描述符用于后续的I/O操作.而对于标准I/O库,操作则是围绕流进行,当用标准I/O库打开或者创建一个文件时,使得一个流与文件相关联.标准I/O库使用了缓冲技术,使用缓冲的目的是尽可能减少使用read和write调用次数,但是效率不高.每次进行读写时候需要复制两次数据.第一次是在内核和标准I/O缓冲之间(调用read和write),第二次是在标准I/O缓冲区和用户程

《APUE》读书笔记—第十一章线程

一个进程在同一时刻只能做一件事情,线程可以把程序设计成在同一时刻能够做多件事情,每个线程处理各自独立的任务.线程包括了表示进程内执行环境必需的信息,包括进程中标识线程的线程ID.一组寄存器值.栈.调度优先级和策略.信号屏蔽字.errno变量以及线程似有数据.进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本.程序的全局内存.栈及文件描述符. 使用线程的好处:(1)为每种事件分配单独的线程.能够简化处理异步事件的代码:(2)多个线程自动地可以访问相同的存储地址空间和文件描述符:(3)

《APUE》读书笔记—第六章数据系统文件和信息

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <time.h> 5 #include <errno.h> 6 #include <string.h> 7 8 int main() 9 { 10 time_t now; 11 struct tm *ptime; 12 char *ptstr; 13 char timebuf[100]