1. 接收传递描述符,demo(fd_read_file.c)
- 创建流管道
- fork并exec
- 父进程等待子进程
- 接收描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <errno.h>
#define HAVE_MSGHDR_MSG_CONTROL
#define BUFFSIZE 8192 /* buffer size for reads and writes */
ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
{
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
#ifdef HAVE_MSGHDR_MSG_CONTROL
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
#else
int newfd;
msg.msg_accrights = (caddr_t) &newfd;
msg.msg_accrightslen = sizeof(int);
#endif
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if ( (n = recvmsg(fd, &msg, 0)) <= 0) {
return(n);
}
#ifdef HAVE_MSGHDR_MSG_CONTROL
if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET)
// err_quit("control level != SOL_SOCKET");
printf("control level != SOL_SOCKET\n");
if (cmptr->cmsg_type != SCM_RIGHTS)
// err_quit("control type != SCM_RIGHTS");
printf("control type != SCM_RIGHTS\n");
*recvfd = *((int *) CMSG_DATA(cmptr));
} else
*recvfd = -1; /* descriptor was not passed */
#else
/* *INDENT-OFF* */
if (msg.msg_accrightslen == sizeof(int))
*recvfd = newfd;
else
*recvfd = -1; /* descriptor was not passed */
/* *INDENT-ON* */
#endif
return(n);
}
/* end read_fd */
int my_open(const char *pathname, int mode)
{
int fd, sockfd[2], status;
pid_t childpid;
char c, argsockfd[10], argmode[10];
/* 创建一个流管道, 返回两个描述符 */
socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
if((childpid = fork()) == 0) {
/* child process */
close(sockfd[0]);
snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);
snprintf(argmode, sizeof(argmode), "%d", mode);
/* 执行openfile程序 */
execl("./openfile", "openfile", argsockfd, pathname, argmode, (char *)NULL);
printf("execl error\n");
}
/* parent process - wait for the child to terminate */
close(sockfd[1]);
waitpid(childpid, &status, 0);
if(WIFEXITED(status) == 0) {
printf("child did not terminate\n");
}
/* 回读f */
if(status = WEXITSTATUS(status) == 0) {
read_fd(sockfd[0], &c, 1, &fd);
} else {
errno = status;
fd = -1;
}
close(sockfd[0]);
return(fd);
}
int main(int argc, char *argv[])
{
int fd, n;
char buff[BUFFSIZE];
if(argc != 2) {
printf("usage: mycat <pathname>\n");
}
/* 以追加方式打开文件,没有就创建 */
if((fd = my_open(argv[1], O_RDWR|O_CREAT|O_APPEND)) < 0) {
printf("cannot open %s\n", argv[1]);
}
while((n = read(fd, buff, BUFFSIZE)) > 0) {
write(STDOUT_FILENO, buff, n);
}
exit(0);
}
2. 打开文件描述符并传递。demo(fd_open_file.c)
- 命令行参数
- 打开文件
- 传递会描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <errno.h>
#define HAVE_MSGHDR_MSG_CONTROL
#define BUFFSIZE 8192 /* buffer size for reads and writes */
ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
{
struct msghdr msg;
struct iovec iov[1];
#ifdef HAVE_MSGHDR_MSG_CONTROL
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA(cmptr)) = sendfd;
#else
msg.msg_accrights = (caddr_t) &sendfd;
msg.msg_accrightslen = sizeof(int);
#endif
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
return(sendmsg(fd, &msg, 0));
}
/* end write_fd */
int main(int argc, char *argv[])
{
int fd;
if(argc != 4) {
printf("openfile <sockfd#> <filename> <mode>\n");
}
printf("file = %s, %s\n", argv[2], argv[3]);
if((fd = open(argv[2], atoi(argv[3]), 0666)) < 0) {
exit((errno > 0) ? errno : 255);
}
/* 向文件中写入测试数据 */
write(fd, "It's a test\n", sizeof("It's a test\n")-1);
lseek(fd, 0, SEEK_SET);
if(write_fd(atoi(argv[1]), "", 1, fd) < 0) {
printf("write_fd error = %d\n", errno);
exit((errno > 0) ? errno : 255);
}
exit(0);
}
3. 演示