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)

 

posted on 2016-12-20 17:15  寒魔影  阅读(261)  评论(0)    收藏  举报

导航