Linux 进程间通讯详解七
上图的一台主机服务器架构的重大缺陷是容易死锁
因为客户端,服务器都往同一消息队列中发送接收消息,假设消息队列已经满了,此时客户端无法向队列中发送消息,阻塞了,
而服务器接收完一条消息后,想向消息队列发送消息,由于消息队列已经满了,也阻塞了,此时就会死锁。
改进型的一台主机服务器架构
建立两个消息队列,一个用于客户端写入服务器接收,一个用于服务器发送客户端接收,这样则永远不会出现死锁
//本机客户端 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <pthread.h> struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1024]; /* message data */ }; int get_msqid(const char *pathname) { if (pathname == NULL) { printf("get_msqid() params not correct !\n"); return -1; } char *pvalue1 = getenv(pathname); if (pvalue1 == NULL) { printf("getenv() failed !\n"); return -1; } key_t sendkey = ftok(pvalue1, 1); if (sendkey == -1) { perror("ftok() err"); return -1; } int msqid = msgget(sendkey, 0666 | IPC_CREAT | IPC_EXCL); if (msqid == -1) { if (errno == EEXIST) { printf("该消息队列已经存在!\n"); msqid = msgget(sendkey, 0666); } else { perror("msgget() err"); return -1; } } return msqid; } void * start_routine(void * arg) { //客户端发送消息队列 int msqid = get_msqid("SENDFILE"); struct msgbuf buf; memset(&buf, 0, sizeof(buf)); buf.mtype = 1; //数据的前4个字节存放当前进程的pid *((int *) buf.mtext) = getpid(); while (fgets(buf.mtext + 4, 1020, stdin) != NULL) { //发送消息队列 if (msgsnd(msqid, &buf, sizeof(int) + strlen(buf.mtext + 4), 0) == -1) { perror("msgsnd() err"); return NULL; } memset(buf.mtext + 4, 0, 1020); } return NULL; } int main(int arg, char * args[]) { //开启多线程 pthread_t thr1; //设置分离线程 pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (pthread_create(&thr1, &attr, start_routine, NULL) != 0) { printf("pthread_create() failed !\n"); return -1; } //客户端接收消息队列 int msqid = get_msqid("RECVFILE"); //recv int rc = 0; struct msgbuf buf; while (1) { memset(&buf, 0, sizeof(buf)); rc = msgrcv(msqid, &buf, 1024, getpid(), 0); if (rc == -1) { perror("msgrcv() err"); break; } printf("服务器有消息到来,消息长度是%d\n",rc); fputs(buf.mtext, stdout); } return 0; }
//本机服务器 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1024]; /* message data */ }; int get_msqid(const char *pathname) { if (pathname == NULL) { printf("get_msqid() params not correct !\n"); return -1; } char *pvalue1 = getenv(pathname); if (pvalue1 == NULL) { printf("getenv() failed !\n"); return -1; } key_t sendkey = ftok(pvalue1, 1); if (sendkey == -1) { perror("ftok() err"); return -1; } int msqid = msgget(sendkey, 0666 | IPC_CREAT | IPC_EXCL); if (msqid == -1) { if (errno == EEXIST) { printf("该消息队列已经存在!\n"); msqid = msgget(sendkey, 0666); } else { perror("msgget() err"); return -1; } } return msqid; } int main(int arg, char * args[]) { /*客户端的发送消息队列,是服务器的接收消息队列*/ int send_msqid = get_msqid("RECVFILE"); if (send_msqid == -1) return -1; int recv_msqid = get_msqid("SENDFILE"); if (recv_msqid == -1) return -1; //接收消息再发送 int rc = 0; struct msgbuf recvbuf; struct msgbuf sendbuf; int pid=0; while (1) { memset(&recvbuf,0,sizeof(struct msgbuf)); memset(&sendbuf,0,sizeof(struct msgbuf)); rc = msgrcv(recv_msqid, &recvbuf, 1024, 1, 0); if(rc==-1) { perror("msgrcv() err"); return -1; } printf("客户端有数据到来!数据的长度是%d\n",rc); //解析数据 pid=*((int *)recvbuf.mtext); sendbuf.mtype=pid; strcpy(sendbuf.mtext,recvbuf.mtext+4); fputs(sendbuf.mtext,stdout); //发送 if(msgsnd(send_msqid,&sendbuf,rc-4,0)==-1) { perror("msgsnd() err"); return -1; } } return 0; }
.SUFFIXES:.c .o CC=gcc SRCS1=test01.c OBJS1=$(SRCS1:.c=.o) EXEC1=clt SRCS2=tec02.c OBJS2=$(SRCS2:.c=.o) EXEC2=ser start:$(OBJS1) $(OBJS2) $(CC) -o $(EXEC1) $(OBJS1) -lpthread $(CC) -o $(EXEC2) $(OBJS2) @echo "-------OK---------" .c.o: $(CC) -Wall -g -o $@ -c $< clean: rm -f $(OBJS1) rm -f $(OBJS2) rm -f $(EXEC1) rm -f $(EXEC2)