2021-9-24 Linux operating system experiment 2: process communication

Posted by hobeau on Fri, 24 Sep 2021 12:17:51 +0200

Experiment 2 of Linux operating system: process communication

Title:

[purpose]

Further improve the ability of C programming in Linux environment, understand and be familiar with a variety of IPC mechanisms supported by Linux. As a multi task and multi process operating system, information interaction between processes is inevitable. Inter process communication can be divided into local inter process communication and remote inter process communication. Local inter process communication mainly includes signal, pipeline, message queue, semaphore, shared memory and other communication methods.

[experimental preparation content]

(1) Read the relevant resources in the Linux interprocess communication section.
(2) Focus on semaphores and shared memory mechanism.

[experiment content]

Read resources, analyze the sample program code, and program in C language to achieve the following requirements.

  • Write a program to select a local inter process communication mechanism to send and receive information between client-side process and server-side process.

Student No.: 021900208 Name: Gao Xu major: Computer Science and technology class: 02

1, Experimental environment:

Oracle VM VirtualBox,Ubuntu(64-bit)

2, Experiment content:

Code part:

my.h

// This experiment realizes three kinds of process communication: 1. Named pipeline FIFO 2. Message queue 3. Shared memory & semaphore

// my.h 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <error.h>
#include <errno.h>
#include <unistd.h>
#include <linux/stat.h>

#define BUFES 80  

// Composition of messages
struct msgbuf  
{
	long int my_type;  // Message type field
	char text[BUFES];  // Data fields for messaging
};

union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *buf_info;
    void *pad;
};

mode_t mode = 00666;  // IPC is set to default mode
char pathname1[] = "/tmp/myfifo";  // FIFO path
char pathname2[] = "/tmp/my_shm";  // Shared memory path
char pathname3[] = "/tmp/my_sem";  // Semaphore path
char proj_id = 'a';  // Used to generate key s

// p operation to obtain semaphore
int sem_p(int semid, int index)
{
    struct sembuf sbuf = {0, -1, IPC_NOWAIT};  // Each sembuf structure describes an operation on a semaphore
    if(index < 0){
        perror("index The specified semaphore does not exist!\n");
        return -1;
    }
    sbuf.sem_num = index;
    if(semop(semid, &sbuf, 1) == -1){
        perror("The semaphore is being processed p An error occurred during the operation!\n");
        return -1;
    }
    return 0;
}

// V operation, release semaphore
int sem_v(int semid, int index)
{
    struct sembuf sbuf = {0, 1, IPC_NOWAIT};  // Each sembuf structure describes an operation on a semaphore
    if(index < 0){
        perror("index The specified semaphore does not exist!\n");
        return -1;
    }
    sbuf.sem_num = index;
    if(semop(semid, &sbuf, 1) == -1){
        perror("The semaphore is being processed v An error occurred during the operation!\n");
        return -1;
    }
    return 0;
}

// Waiting semaphore
int wait_sem(int semid, int index)
{
    while(semctl(semid, index, GETVAL, 0) == 0) ;
    return 1;
}

Client program code myclient.c:

// myclient.c

#include "my.h"

int running = 1;

void  stop()
{
	running = 0;
}

int main(int argc, char *argv[])
{
    FILE *fp;  //Named pipe file pointer
    const int flag1 = IPC_CREAT | IPC_EXCL | mode;  // Create the corresponding IPC, and return - 1 if it already exists
    const int flag2 = IPC_CREAT | mode;  // Open the corresponding IPC. If it does not exist, create it
    struct msgbuf msg_sbuf;  // Messages delivered by message queuing
    struct msqid_ds msg_info;  // Used to set or return message queue information
    union semun arg;  // Last argument to function semid
    key_t semkey, shmkey;  // Semaphores, shared memory keys
    int semid, shmid,msgid;  // Semaphore ID, shared memory ID, message queue ID
    int sem_members=4;  // The number of semaphores is 4. Signal 0 is whether someone is occupying the client shared memory, signal 1 is whether someone is occupying the server shared memory, signal 2 is whether the client shared memory is readable, and signal 3 is whether the server shared memory is readable
    int reval;  // Accept the return value of message queue manipulation function msgctl
    char writebuf[BUFES];  // Write buffer for named pipe  
    char write_str[BUFES];  // Shared memory buffer
    char *shmaddr;  // Storage shared memory interface
    signal(SIGINT, stop);  // Register SIGINT signal
    while (running)
    {
        if((fp=fopen(pathname1, "w")) == NULL)
	    {
		    printf("Failed to open named pipe \n");
		    exit(1);
	    }
        printf("Please enter: ");
        fgets(writebuf, BUFES, stdin);
        if(strncmp(writebuf, "end", 3) == 0)
        {
            printf("End signal received,End of named pipe communication \n");
            running = 0;
        }
        if(fputs(writebuf, fp) == EOF)
		{
			printf("Failed to write to named pipe \n");
			exit(1);
		}
        fclose(fp);
    }
    running = 1;
    while(running);
    running = 1;
    printf("receive SIGINT Signal, and then start message queue communication \n");   
    printf("-------------------------------------------------------------------------\n");
    if((msgid=msgget((key_t)1111, flag2)) == -1)  // Open the message queue with the key value of 1234. If it does not exist, create it
    {
        printf("establish/Failed to open message queue! \n");
        exit(1);    
    }
    else printf("Message queue created successfully \n");
    while (running)
    {
		printf("Please enter: ");
		fgets(msg_sbuf.text, BUFES, stdin);  // Read in messages entered on the keyboard
		msg_sbuf.my_type = 1;	
		if(msgsnd(msgid, (void *) &msg_sbuf, BUFES, 0) == -1)  // send message
		{
			printf("Failed to send message!\n");
			exit(1);
		}
		if(strncmp(msg_sbuf.text, "end", 3) == 0)  // Enter end to end the program
		{
            printf("End signal received,End of message queue communication \n");
            running = 0;
        }
    }
    if((reval=msgctl(msgid, IPC_STAT, &msg_info)) == -1)
    {
        printf("Failed to get message queue information! \n");
        exit(1);
    }
    printf("Message queue information: \n");
    printf("Message queue capacity: %ld \n", msg_info.msg_qbytes);
    printf("Last execution msgsnd Process of function ID Yes:%d \n", msg_info.msg_lspid);
    printf("Last execution msgrcv Process of function ID Yes:%d \n", msg_info.msg_lrpid);
	if(msgctl(msgid, IPC_RMID, 0)==-1)  //  Delete message queue
	{
		printf("Failed to delete message queue! \n");
		exit(1);
	}
    else printf("Message queue deleted successfully\n");
    printf("Next, start sharing memory&Semaphore communication \n"); 
    printf("-------------------------------------------------------------------------\n");
    if((shmkey = ftok(pathname2, proj_id)) == -1)
    {
        perror("Failed to return shared memory key value!\n");
        exit(1);
    }
    else printf("Get shared memory key value succeeded!\n");
    if((shmid = shmget(shmkey, BUFES, flag2)) == -1){
        perror("establish/Failed to open shared memory!\n");
        exit(1);
    }
    else printf("Open shared memory successfully!\n");
    if((shmaddr=shmat(shmid, (char*)0, 0)) == (char *)-1)
    {
        perror("Failed to attach shared memory!\n");
        exit(1);
    }
    else printf("Attaching shared memory succeeded!\n");
    if((semkey = ftok(pathname3, proj_id)) == -1)
    {
        perror("Failed to return semaphore key value!\n");
        exit(1);
    }
    else printf("Successfully obtained semaphore key value!\n");
    if((semid = semget(semkey, sem_members, flag2)) == -1)  // Open the semaphore set whose key value is semkey. If it does not exist, create it and return the semaphore set identifier. members is the number of semaphores in the semaphore set.
    {  
        perror("Failed to open semaphore!\n");
        exit(1);
    }
    else printf("Open semaphore successfully!\n");
    arg.val = 1;
    for(int index = 0; index < sem_members; index++)
    {
        semctl(semid, index, SETVAL, arg);
        if(index==0) arg.val = 0;
    }
    printf("Initialization of semaphore succeeded!\n");
    while(1)
    {
        wait_sem(semid, 0);  // Wait for the client shared memory writable semaphore to be obtained
        sem_p(semid, 0);  // Get client writable semaphore
        printf("send out:");
        fgets(write_str, BUFES, stdin);
        int len = strlen(write_str);
        write_str[len] = '\0';
        strcpy(shmaddr, write_str);
        sem_v(semid, 1);  // Pass a shared memory readable semaphore to the server
        if(strncmp(write_str, "end", 3) == 0)  // Enter end to end the program
		{
            printf("End signal received,Shared memory&End of semaphore communication \n");
            break;
        }
        wait_sem(semid, 3);  // Wait for the client shared memory readable semaphore to be obtained
        sem_p(semid, 3);  // Gets the client shared memory readable semaphore
        printf("receive:%s", shmaddr);
        sem_v(semid, 0);  // Pass a shared memory writable semaphore to the client
        if(strncmp(shmaddr, "end", 3) == 0)  // Enter end to end the program
		{
            printf("End signal received,Shared memory&End of semaphore communication \n");
            break;
        }
    }
    sleep(3);
    if((semctl(semid, 0, IPC_RMID))==0)  printf("Successfully deleted semaphore \n");
    else printf("Failed to delete semaphore");
    if((shmctl(shmid, IPC_RMID, NULL))==0) printf("Delete shared memory succeeded \n");
    else printf("Failed to delete shared memory");
    return 0;
}

Server program code myserver.c

// myserver.c 

#include "my.h"

int running = 1;

void  stop()
{
	running = 0;
}

int main(int argc, char *argv[])
{       
    FILE *fp;  //Named pipe file pointer
    const int flag1 = IPC_CREAT | IPC_EXCL | mode;  // Create the corresponding IPC, and return - 1 if it already exists
    const int flag2 = IPC_CREAT | mode;  // Open the corresponding IPC. If it does not exist, create it
    struct msgbuf msg_rbuf;  // Messages delivered by message queuing
    union semun arg;  // Last argument to function semid
    key_t semkey, shmkey;  // Semaphores, shared memory keys
    long int msg_to_receive = 0;  // Accept the first message in the message queue
    int msgid,semid, shmid;  // Semaphore ID, shared memory ID, message queue ID
    int sem_members = 4;  // The number of semaphores is 4. Signal 0 is whether someone is occupying the client shared memory, signal 1 is whether someone is occupying the server shared memory, signal 2 is whether the client shared memory is readable, and signal 3 is whether the server shared memory is readable  
	char readbuf[BUFES];  // Read buffer for named pipe 
    char write_str[BUFES];  // Shared memory buffer
    char *shmaddr;  // Storage shared memory interface
    signal(SIGINT, stop);  // Register SIGINT signal
    if((mkfifo(pathname1, mode)) < 0)
    {
        perror("Failed to create named pipe!\n");
        exit(1);
    }
    else printf("You have successfully created a named pipe \n");
    while(running)
    {
        if((fp = fopen(pathname1, "r")) < 0)
        {
            printf("Failed to open named pipe \n");
		    exit(1);
        }
        if(fgets(readbuf, BUFES, fp) != NULL)
        {
			printf("Read string: %s", readbuf);
			fclose(fp);
        }
        else
		{
			if(ferror(fp))
			{
				printf("Failed to read named pipe \n");
				exit(1);
			}
		}
        if(strncmp(readbuf, "end", 3) == 0)
        {
            printf("End signal received,End of named pipe communication \n");
            running = 0;
        }
    }
    running = 1;
    while(running);
    running = 1;
    printf("receive SIGINT Signal, and then start message queue communication \n"); 
    printf("-------------------------------------------------------------------------\n");
    if((msgid=msgget((key_t) 1111, flag2)) == -1)  // Open the message queue with the key value of 1234. If it does not exist, create it
    {
        printf("establish/Failed to open message queue! \n");
        exit(1);    
    }
	while(running)
	{
		if(msgrcv(msgid, (void *) &msg_rbuf, BUFES, msg_to_receive, 0) == -1)  //When receiving messages, the last parameter is to set the default mode
		{
			printf("Failed to get message!\n");
			exit(1);
		}
		printf("Message received : %s", msg_rbuf.text);
		if(strncmp(msg_rbuf.text, "end", 3) == 0)  // Enter end to end the program
		{
            printf("End signal received,End of message queue communication \n");
            running = 0;
        }
	}
    printf("Next, start sharing memory&Semaphore communication \n"); 
    printf("-------------------------------------------------------------------------\n");
    if((shmkey = ftok(pathname2, proj_id)) == -1)
    {
        perror("Failed to return shared memory key value!\n");
        exit(1);
    }
    else printf("Get shared memory key value succeeded!\n");
    if((shmid = shmget(shmkey, BUFES, flag2)) == -1){
        perror("establish/Failed to open shared memory!\n");
        exit(1);
    }
    else printf("Open shared memory successfully!\n");
    if((shmaddr=shmat(shmid, (char*)0, 0)) == (char *)-1)
    {
        perror("Failed to attach shared memory!\n");
        exit(1);
    }
    else printf("Attaching shared memory succeeded!\n");
    sleep(2);
    if((semkey = ftok(pathname3, proj_id)) == -1)
    {
        perror("Failed to return semaphore key value!\n");
        exit(1);
    }
    else printf("Successfully obtained semaphore key value!\n");
    if((semid = semget(semkey, sem_members, flag2)) == -1)  // Open the semaphore set whose key value is semkey. If it does not exist, create it and return the semaphore set identifier. members is the number of semaphores in the semaphore set.
    {  
        perror("Failed to open semaphore!\n");
        exit(1);
    }
    else printf("Open semaphore successfully!\n");
    while(1)
    {
        wait_sem(semid, 1);  // Wait for the server shared memory readable semaphore to be obtained
        sem_p(semid, 1);  // Gets the server shared memory readable semaphore
        printf("receive:%s", shmaddr);
        sem_v(semid, 2);  // Pass a shared memory writable semaphore to the server
        if(strncmp(shmaddr, "end", 3) == 0)  // Enter end to end the program
		{
            printf("End signal received,Shared memory&End of semaphore communication \n");
            break;
        }
        wait_sem(semid, 2);  // Wait for the server shared memory writable semaphore to be obtained
        sem_p(semid, 2);  // Get server shared memory writable semaphore
        printf("send out:");
        fgets(write_str, BUFES, stdin);
        int len = strlen(write_str);
        write_str[len] = '\0';
        strcpy(shmaddr, write_str);
        sem_v(semid, 3);  // Pass a shared memory readable semaphore to the client
        if(strncmp(write_str, "end", 3) == 0)  // Enter end to end the program
		{
            printf("End signal received,Shared memory&End of semaphore communication \n");
            break;
        }
    }
    return 0;
}

Screenshot of experimental results:


3, Experiment summary:

1. Program idea:

This experiment compiled: client client program and server program
The main purpose is to achieve:
① server calls mkfifo to create a named pipe
② The client sends information to the server one way through the named pipe
③ After receiving the SIGINT signal, the two processes close the named pipe and enter the message queue communication phase
④ The client sends information to the server one way through the message queue
(5) call the msgctl function to see part of the message queue before ending message queuing communication.
⑥ The client and server enter the shared memory semaphore communication phase, open the shared memory and semaphore, and the number of semaphores is 4. The client completes the initialization operation
⑦ Call the functions encapsulated in my.h to realize the sequential execution of client sending - > server receiving - > server sending - > client receiving
⑧ Delete the shared memory and semaphore, and the process ends.

2. What are the self-taught knowledge in this experiment:

① Pipeline

② Named pipe

③ ftok function

④ open function

⑤ Message queue

⑥ Shared memory

⑦ Semaphore

3. Difficulties and solutions in this experiment:

① Error reporting for the second time using mkfifo

mkfifo cannot have a file with the same name, so the fifo file generated by the previous execution should be deleted in the second execution.

②flag=IPC_CREAT | IPC_EXCL | mode cannot be defined in my.h

Solution: abandon the definition in my.h, but define it in both client and server programs.

③ When deleting message queues, shared memory and semaphores, the other party does not exit the loop

Solution: using the method of the last experiment, call the sleep function.

④ Shared memory and semaphore path error

Solution: shmget of shared memory and semaphore has been. The parameter pathname of semget must be the existing path. You can create a folder with the corresponding file name.

⑤ Because three mechanisms are implemented at the same time, the number of lines of code in this experiment is too many

Solution: None

4. Attach the execution flow chart of this experimental procedure:

Topics: C Linux Ubuntu