Linux进程间通信编程

任务1:

要求:编写程序task71.c实现进程的管道通信。父进程创建两个子进程,父子进程通过管道来传送数据。两个子进程P1和P2分别向管道各写一句话:

Child P1 is sending My name <您的姓名XXX>!

Child P2 is sending the current time <当前系统时间,包括年月日时分秒>! 

父进程从管道中读出两个来自子进程的信息并显示。

提示:获取系统时间的函数是”time_t  time(time_t *t);”,将time_t格式时间转换成字符串格式的函数是”char *ctime(const time_t *timep);” 

设计思想:

通过管道重定向来实现进程之间的信息交流,父进程使用FOR循环来读取2次数据。

#include "wrapper.h"
int main()
{
    int fds[2];
    int pid11, pid12;
    char buf[1024];
    char cpid1[] = "Child P1 is sending My name 泠霖凛!";
    char cpid2[80];
    struct tm *newtime;
    time_t t = time(NULL);
    newtime = localtime(&t);
    strftime(cpid2, 100, "Child P2 is sending<%Y年%m月%d日%H时%M分%S秒>", newtime);
    pipe(fds);
    pid11 = fork();
    if (pid11 == 0)
    {
        close(fds[0]);
        write(fds[1], cpid1, strlen(cpid1));
        close(fds[1]);
        dup2(4, 0);
        exit(0);
    }
    else
    {
        pid12 = fork();
        if (pid12 == 0)
        {
            close(fds[0]);
            write(fds[1], cpid2, strlen(cpid2));
            close(fds[1]);
            dup2(4, 0);
            exit(0);
        }
        else
        {
            for (int i = 0; i < 2; i++)
            {
                dup(0);
                close(0);
                dup(fds[0]);
                read(fds[0], buf, 1024);
                printf("\b%s\n", buf);
                close(fds[0]);
                close(fds[1]);
            }
        }
    }
}

任务2:

要求:编写消息队列通信程序task72s.c和task72c.c,利用消息队列通信实现一个简单的客户/服务器应用,多个客户进程task72c可并发地向服务器进程发送消息,服务器task72s向每个客户发送消息接收回执。比如进程PID为1234的客户端发送的消息为”hello from Process 1234”,服务器收到该消息后发回消息为“receipt of hello from <您的姓名xxx>’s server to Process 1234”

设计思想:

使用消息队列来传递信息,消息队列的信息是存放在系统里的,每个消息的值需要确定类型,不然会传递失败;要注意服务器会和客户端冲突抢信息,因此服务器发送信息后需要睡眠1秒来规避冲突。

task72s.c:

#include "wrapper.h"
char *mygetpid(char *str);
char *getfirst(char *str);
typedef struct MESSAGE
{
    long mtype;
    char mtext[512];
} mymsg, *pmymsg;
int main(int argc, char *argv[])
{
    int rtn;
    int msqid;
    key_t key;
    mymsg msginfo;
    char first[512];
    char buf[512];
    if (argc != 2)
    {
        fprintf(stderr, "请以./task72s<key>的形式运行给出的消息队列键值\n");
        exit(0);
    }
    sscanf(argv[1], "%x", &key);
    msqid = msgget(key, 0644);
    msginfo.mtype = 1;
    while (1)
    {
        memset(msginfo.mtext, 0, sizeof(msginfo.mtext));
        rtn = msgrcv(msqid, (pmymsg)&msginfo, sizeof(msginfo.mtext), 1, 0);
        if (rtn == -1)
            continue;
        strcpy(first, msginfo.mtext);
        printf("收到消息:%s\n", first);
        strcat(buf, "receipt of ");
        strcat(buf, getfirst(msginfo.mtext));
        strcat(buf, " from 泠霖凛's server to Process ");
        strcat(buf, mygetpid(first));
        strcpy(msginfo.mtext, buf);
        rtn = msgsnd(msqid, &msginfo, strlen(msginfo.mtext), 0);
        sleep(1);
        memset(buf, 0, sizeof(buf));
        if (strcmp(first, "close") == 0)
        {
            return 0;
        }
    }
}
//服务端提取消息对应的线程
char *mygetpid(char *str)
{
    char *p[21];
    memcpy(p, str, 4);
    char *t;
    p[0] = strtok(str, " ");
    int i = 0;
    while (p[i] != NULL)
    {
        i++;
        p[i] = strtok(NULL, " ");
    }
    t = p[i - 1];
    return t;
}
char *getfirst(char *str)
{
    char *p[21];
    memcpy(p, str, 4);
    char *t;
    p[0] = strtok(str, " ");
    t = p[0];
    return t;
}

task72c.c:

#include "wrapper.h"
typedef struct MESSAGE
{
    long mtype;
    char mtext[512];
} mymsg, *pmymsg;
char mbuf[1024];
int main(int argc, char *argv[])
{
    int rtn;
    int msqid;
    key_t key;
    int mypid = (int)(getpid());
    char cpid[10];
    sprintf(cpid, "%d", mypid);
    if (argc != 3)
    {
        fprintf(stderr, "程序启动方式为./task72c<消息队列键值><待发送消息>\n");
        exit(0);
    }
    sscanf(argv[1], "%x", &key);
    msqid = msgget(key, 0644);
    mymsg msg;
    msg.mtype = 1;
    strcat(argv[2], " from Process ");
    strcat(argv[2], cpid);
    strcpy(msg.mtext, argv[2]);
    rtn = msgsnd(msqid, &msg, strlen(msg.mtext), 0);
    printf("you send a message \"%s\" to msq %d\n", argv[1], msqid);
    memset(msg.mtext, 0, sizeof(msg.mtext));
    rtn = msgrcv(msqid, (pmymsg)&msg, sizeof(msg.mtext), 1, 0);
    printf("%s\n", msg.mtext);
    return 0;
}

任务3:

要求:编写程序task73.c,父进程创建两个子进程P1和P2,P1通过共享内存将1、2、3、…、10依次发送给进程P2输出显示,每次发送一个,父子进程间利用IPC信号量同步。

设计思想:

使用共享内存来实现进程P1与P2之间的交流,使用IPC信号量来实现进程之间的同步互斥。

#include "wrapper.h"
int main(int argc, char *argv[])
{
    int sig = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
    union semun
    {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    } arg_sem;
    arg_sem.val = 1;
    semctl(sig, 0, SETVAL, arg_sem);
    struct sembuf sem, fsem;
    sem.sem_num = 0;
    sem.sem_op = -1;
    sem.sem_flg = SEM_UNDO;
    fsem.sem_num = 0;
    fsem.sem_op = 1;
    fsem.sem_flg = SEM_UNDO;

    int pid11, pid12;
    int rtn;
    int shmid;
    char buf[2];
    key_t key;
    void *shmptr;
    if (argc <= 1)
    {
        fprintf(stderr, "请以./task73<key>的形式运行,给出消息队列的键值\n");
        exit(1);
    }
    sscanf(argv[1], "%x", &key);
    shmid = shmget(key, 4096, IPC_CREAT | 0644);
    pid11 = fork();
    if (pid11 == 0)
    {
        for (int i = 1; i <= 10; i++)
        {
            semop(sig, &sem, 1);
            shmptr = shmat(shmid, 0, 0);
            sprintf(buf, "%d", i);
            memcpy(shmptr, buf, strlen(buf));
            shmdt(shmptr);
            semop(sig, &fsem, 1);
        }
    }
    else
    {
        pid12 = fork();
        if (pid12 == 0)
        {
            for (int i = 1; i <= 10; i++)
            {
                semop(sig, &sem, 1);
                shmptr = shmat(shmid, 0, 0);
                printf("%s\n", (char *)shmptr);
                shmdt(shmptr);
                semop(sig, &fsem, 1);
            }
        }
        else
        {
            sleep(1);
            exit(0);
        }
    }
}

  • 14
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值