• 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 !
    ");
            return -1;
        }
        char *pvalue1 = getenv(pathname);
        if (pvalue1 == NULL)
        {
            printf("getenv() failed !
    ");
            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("该消息队列已经存在!
    ");
                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 !
    ");
            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
    ",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 !
    ");
            return -1;
        }
        char *pvalue1 = getenv(pathname);
        if (pvalue1 == NULL)
        {
            printf("getenv() failed !
    ");
            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("该消息队列已经存在!
    ");
                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
    ",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)
  • 相关阅读:
    控制翻转与容器
    构造函数传递参数
    bean属性检查
    tomcat源码阅读14
    Block Formatting Context
    IE 兼容性问题的处理
    JavaScript 的原型与继承
    IE 多版本测试工具 IETester
    callee,caller,call,apply
    HDOJ2175 汉诺塔IX
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/6203411.html
Copyright © 2020-2023  润新知