unix提供的各种IPC,包括管道和套接字还有信号量,这里介绍一种高级的IPC-UNIX域套接字机制
UNIX域套接字
用于在同一计算机上运行的进程之间的通信,虽然因特网域套接字可用于同一目的,但UNIX域套接字的效率更高,UNIX域套接字仅仅复制数据,并不执行协议处理,不需要添加或删除网络报头。
UNIX域套接字数据报服务是可靠的,既不会丢失报文也不会传递出错,可以使用其面向网络的域套接字接口(socket)或者使用socketpair函数来创建一对无命名、相互连接的UNIX域套接字。
#include <sys/socket.h> int socketpair(int domain,int type,int protocol,int sockfd[2]);
一对相互连接的UNIX域安通戒子可以起到全双工管道的作用:可同时读和写。
例子:轮询XSI消息队列
对每个消息队列使用一个线程,每个线程都会在msgrcv调用中阻塞,当消息到达时,线程会把他写入一个unix域套接字的一端:fd[1]。当poll指示套接字可以读取数据时,应用程序使用这个套接字的另外一端来读取消息,fd[0]。
#include "apue.h" #include <poll.h> #include <pthread.h> #include <sys/msg.h> #include <sys/socket.h> #define NQ 3 #define MAXMSZ 512 #define KEY 0x123 struct threadinfo{ int qid; int fd; }; struct mymesg{ long mtype; char mtext[MAXMSZ]; }; void *helper(void *arg){ int n; struct mymesg m; struct threadinfo *tip=arg; for(;;){ memset(&m,sizeof(m)); if((n=msgrcv(tip->qid,&m,MAXMSZ,MSG_NOERROR))<0) printf("msgrcv error"); if(write(tip->fd,m.mtext,n)<0) printf("write error"); } } int main() { int i,n,err; int fd[2]; int qid[NQ]; struct pollfd pfd[NQ]; struct threadinfo ti[NQ]; pthread_t tid[NQ]; char buf[MAXMSZ]; for(i=0;i<NQ;i++){ if((qid[i]=msgget((KEY+i),IPC_CREAT|0666))<0) printf("msgget error"); printf("queue ID %d is %d\n",i,qid[i]); if(socketpair(AF_UNIX,SOCK_DGRAM,fd)<0) printf("socketpair error"); pfd[i].fd=fd[0]; pfd[i].events=POLLIN; ti[i].qid=qid[i]; ti[i].fd=fd[1]; if((err=pthread_create(&tid[i],NULL,helper,&ti[i]))!=0) printf("pthread_create error"); } for(;;){ if(poll(pfd,NQ,-1)<0) printf("poll error"); for(i=0;i<NQ;i++){ if(pfd[i].revents & POLLIN){ if((n=read(pfd[i].fd,buf,sizeof(buf)))<0) printf("read error"); buf[n]=0; printf("queue id %d,message %s\n",qid[i],buf); } } } exit(0); }
使用下列程序给上面程序测试发送消息:
#include "apue.h" #include <stdio.h> #include <sys/msg.h> #define MAXMSZ 512 struct mymesg { long mtype; char mtext[MAXMSZ]; }; int main(int argc,char *argv[]) { key_t key; long qid; size_t nbytes; struct mymesg m; if(argc!=3){ fprintf(stderr,"usage: sendmsg KEY message\n"); exit(1); } key=strtol(argv[1],0); if ((qid=msgget(key,0))<0) printf("can't open queue key\n"); memset(&m,sizeof(m)); strncpy(m.mtext,argv[2],MAXMSZ-1); nbytes=strlen(m.mtext); m.mtype=1; if(msgsnd(qid,nbytes,0)<0) printf("can't send message\n"); exit(0); }
程序需要两个参数:消息队列关联的键值和一个消息字符串。
运行如下:
c@c:~/process_com$ ./1 queue ID 0 is 0 queue ID 1 is 32769 queue ID 2 is 65538
c@c:~/process_com$ ./2 0x123 "www"
queue id 0,message www