Example.No.1:
通过socketpair打开两个连接起来的Unix套接字,一个用于进程本身读取内容,并输出到进程本身的标准输出,另一个则用于子进程传递通过Unix套接字发送excel的一个进程打开的文件描述符,通过sendmsg的辅助数据传递
进程本身代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <fcntl.h>
#define BUFSIZE 4096
int read_fd(int fd,void* ptr,size_t nbytes,int* recvfd ) {
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
}control_un;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
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;
}
struct cmsghdr* cmptr;
if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET) {
printf("control level != SOL_SOCKET\n");
exit(1);
}
if (cmptr->cmsg_type != SCM_RIGHTS) {
printf("control level != SCM_RIGHTS\n");
exit(1);
}
*recvfd = *(int*)CMSG_DATA(cmptr);
}else {
*recvfd = -1;
}
}
int my_open(char* pathname,int mode) {
int fd,sockfd[2],status;
char c;
if (socketpair(AF_LOCAL,SOCK_STREAM,0,sockfd) < 0) {
printf("setsockpair error: %s\n",strerror(errno));
exit(1);
}
int childpid;
if ((childpid = fork()) < 0) {
printf("fork error: %s\n",strerror(errno));
exit(1);
}else if (childpid == 0) {
char argsockfd[10],argmode[10];
snprintf(argsockfd,sizeof(argsockfd),"%d",sockfd[1]);
snprintf(argmode,sizeof(argmode),mode);
execl("./openfile","openfile",argsockfd,pathname,argmode,(char*)NULL);
}
close(sockfd[1]);
if (waitpid(childpid,&status,0) < 0) {
printf("waitpid error: %s\n",strerror(errno));
exit(1);
}
if (WIFEXITED(status) == 0) {
printf("child process did not terminate\n");
exit(1);
}
if ((status = WEXITSTATUS(status)) == 0) {
if (read_fd(sockfd[0],&c,1,&fd) < 0) {
printf("read_fd error\n");
exit(1);
}
}else {
errno = status;
fd = -1;
}
close(sockfd[0]);
return fd;
}
int main(int argc,char** argv) {
if (argc != 2) {
printf("please add <pathname>\n");
exit(1);
}
int fd;
if ((fd = my_open(argv[1],O_RDONLY)) < 0) {
printf("can't open %s\n",argv[1]);
exit(1);
}
char buf[BUFSIZE];
int n;
while ((n = read(fd,buf,BUFSIZE)) > 0) {
if (write(STDOUT_FILENO,n) != n) {
printf("write error: %s\n",strerror(errno));
exit(1);
}
}
return 0;
}
openfile进程代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int write_fd(int fd,int sendfd) {
struct msghdr msg;
struct iovec iov[1];
union {
struct cmsghdr cmsg;
char controls[CMSG_SPACE(sizeof(int))];
}control_un;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = control_un.controls;
msg.msg_controllen = sizeof(control_un.controls);
struct cmsghdr* cmptr;
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;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
return sendmsg(fd,0);
}
int main(int argc,char** argv) {
if (argc != 4) {
printf("please check your input-arguments\n");
exit(1);
}
int fd;
if ((fd = open(argv[2],atoi(argv[3]))) < 0) {
printf("open %s fail: error reason: %s\n",argv[2],strerror(errno));
exit(1);
}
int n;
if ((n = write_fd(atoi(argv[1]),"",fd)) < 0) {
exit(n);
}
exit(0);
}