APUE读书笔记-17高级进程通信(9)
接口定义
我们定义如下的三个函数来发送和接收文件描述符号,在本节的后面,我们将会展示对于流和套接字的这三个函数的代码。
如果进程(通常是服务进程)想要发送文件描述符号给另外一个进程,那么调用send_fd或者send_err。
#include "apue.h"
int send_fd(int fd, int fd_to_send);
int send_err(int fd, int status, const char *errmsg);
两者返回:如果成功返回0,如果错误返回1。
函数send_fd通过fd代表的unix域的套接字或者stream pipe来发送文件描述符号"fd_to_send"。
我们将要使用s-pipe来表示全双工的通信通道,这个通道可以采用streams pipe或者unix域套接字实现。
send_err函数使用fd发送errmsg,并且fd后面接着的status状态值必须在范围1到255之间。
进程(通常客户进程)如果等待接收文件描述符号则调用recv_fd。
int recv_fd(int fd, ssize_t (*userfunc)(int, const void *, size_t));
返回:如果成功返回文件描述符号,如果错误返回负数。
客户进程调用recv_fd来接收一个文件描述符号。如果所有的过程成功(发送者调用send_fd),那么会返回一个非负数的文件描述符号作为函数的返回值。否则,返回值表示send_err发出的状态(在1到255区间的负数)。另外,如果服务进程发送一个错误的消息,那么客户进程的userfunc函数将会被调用来处理这个消息。userfunc函数的第一个参数是STDERR_FILENO,后面接着的是指向错误消息的指针以及它的长度。userfunc函数的返回值就是写入的字节数目或者表示错误时候的负数。一般来说客户进程会指定一个常用的write函数作为userfunc。
接口实现策略
我们自己实现了一个这三个函数所使用的协议。
发送的时候
- 发送文件描述符号时,send_fd发送两个字节的0,后面接着实际的文件描述符号。 (即
0-0-fd_to_send
) - 发送错误时,send_err发送错误消息errmsg,后面接着一个字节的0,然后是状态字节的绝对值(从1到255), (即
errmsg-0-errstatus
)。
如果发送文件描述符号,那么开始0实际就是null,所以相当于一个"空字符串+0+描述符号";而不发送文件描述符号相当于"错误消息字符串+状态绝对值"。
接收的时候
-
函数recv_fd读取s-pipe上所有内容直到遇到一个null字节,此刻读取到的字符都会被传递到调用者的userfunc中。
此时,接收了
errmsg-0
, 还剩下errstatus
; 或0
, 还剩下0-fd_to_send
。
recv_fd的下一个字节就是状态字节,
- 如果状态字节是0,那么会传递一个文件描述符号(此时是还剩下
0-fd_to_send
的情况); - 否则不会接收到文件描述符号(此时是还剩下
status
的情况)
send_err函数
函数send_err在写错误消息到s-pipe之后调用send_fd函数。如下所示:
#include "apue.h"
/*
* Used when we had planned to send an fd using send_fd(),
* but encountered an error instead. We send the error back
* using the send_fd()/recv_fd() protocol.
*/
int send_err(int fd, int errcode, const char *msg)
{
int n;
if ((n = strlen(msg)) > 0)
if (writen(fd, msg, n) != n) /* send the error message */
return(-1);
if (errcode >= 0)
errcode = -1; /* must be negative */
if (send_fd(fd, errcode) < 0)
return(-1);
return(0);
}
下面将看到函数send_fd和recv_fd函数的实现。将文件描述符号通过基于流的管道进行传递。