操作系统大作业---信号量+shell脚本+socket

1、设自行车生产线上有一只箱子,其中有N个位置(N≥3),每个位置可存放一个车架或一个车轮,又设有三名工人,其活动分别为:
工人1活动
do{
加工一个车架;
车架放入箱中;
}while(1)	工人2活动
do{
加工一个车轮;
车轮放入箱中;
}while(1)	工人3活动
do{
箱中取一个车架;
箱中取两个车轮;
组装一台车;
}while(1)
用信号量PV操作编程实现三个工人的合作,不能出现死锁。要求N的大小可自定义,显示自行车生产组装的过程。(25分)

分析过程:
互斥关系:
1、对缓冲区(箱子)的访问要互斥的进行
同步关系:
1、只有箱子有空位时工人1或者工人2才能把车架放入箱子中
2、只有箱子中有超过1个车架和2个车轮时,工人3才能组装1台车

分析中涉及到一个问题
如果箱子中因为线程竞争出现没有车架或者低于2个车轮的情况就会发生死锁,为了防止出现这种情况,需要把箱子分为2部分,一部分放车轮,一部分放车架,使其空间比例为2:1。对于缓冲区设置一个循环队列,对于循环队列%3=0的位置放车架,%3!=0的位置放车轮,这样就解决了死锁问题。
需要四个信号量bike_frame_sem, bike_wheel_sem, product_sem, box_sem分别对应工人1生产车架,工人2生产车轮,工人3组装车,以及互斥访问盒子

源码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define MAX_N 12 // 箱子中位置的最大值
#define TRUE 1
#define FALSE 0

sem_t bike_frame_sem, bike_wheel_sem, product_sem, box_sem; // 四个信号量
int bike_frame_count = 0, bike_wheel_count = 0, product_count = 0; // 全局变量
int full_queue[MAX_N]; // 队列变量,使用环形队列

void *bike_frame_worker(void *arg)
{
	
    while (TRUE)
    {
    	sem_wait(&bike_frame_sem);
        // 队列中 %3 == 0的位置放车架 
		for(int i = 0; i < MAX_N; i += 3)
			if(!full_queue[i]){
				full_queue[i] = 1;
				break;
			}
		bike_frame_count ++;
		sem_wait(&box_sem);
		printf("Successfully Manufacturing a frame!\n");
		sem_post(&box_sem);
		sleep(1); // 加工车架需要3秒钟
        // 互斥访问 
        sem_wait(&box_sem);
		if(bike_wheel_count >= 2 && bike_frame_count >= 1)
        {
        	bike_wheel_count -= 2;
        	bike_frame_count -= 1;
        	sem_post(&product_sem);	
		}
		sem_post(&box_sem);	
    }
}

void *bike_wheel_worker(void *arg)
{
	
    while (TRUE)
    { 
    	sem_wait(&bike_wheel_sem);
        // 队列中 %3 != 0的位置放车轮 
		for(int i = 0; i < MAX_N; i ++)
		{
			if(i % 3 == 0) continue;
			if(!full_queue[i]){
				full_queue[i] = 2;
				break;
			}
		}
        bike_wheel_count ++;
        
        sem_wait(&box_sem);
        printf("Successfully Manufacturing a wheel!\n");
        sem_post(&box_sem);
		sleep(1); // 加工车轮需要3秒钟
        // 互斥访问 
        sem_wait(&box_sem);
		if(bike_wheel_count >= 2 && bike_frame_count >= 1)
        {
        	bike_wheel_count -= 2;
        	bike_frame_count -= 1;
        	sem_post(&product_sem);	
		}
		sem_post(&box_sem);	
    }
}

void *bike_assembler(void *arg)
{
    while (TRUE)
    {
    	sem_wait(&product_sem);
    	// 从队列中取出 1个 车架 
    	for(int i = 0; i < MAX_N; i ++)
    		if(full_queue[i] == 1)
    		{
    			full_queue[i] = 0;
    			break;
			}
		// 从队列中取出 1个 车轮 
		for(int i = 0; i < MAX_N; i ++)
    		if(full_queue[i] == 2)
    		{
    			full_queue[i] = 0;
    			break;
			}
    	for(int i = 0; i < MAX_N; i ++)
		if(full_queue[i] == 2)
		{
			full_queue[i] = 0;
			break;
		}
		product_count++;
		sem_wait(&box_sem);
		printf("Successfully Assembled No.%d bike! frame count = %d, wheel count = %d, product count = %d\n", product_count, bike_frame_count, bike_wheel_count, product_count);
        sem_post(&box_sem);
		sem_post(&bike_frame_sem);
        sem_post(&bike_wheel_sem);
        sem_post(&bike_wheel_sem);
    }
}

int main()
{
    sem_init(&bike_frame_sem, 0, MAX_N / 3); // 创建并初始化信号量,表示车架数量
    sem_init(&bike_wheel_sem, 0, MAX_N / 3 * 2); // 创建并初始化信号量,表示车轮数量
    sem_init(&product_sem, 0, 0); // 创建并初始化信号量,表示已经生产的自行车数量
	sem_init(&box_sem, 0, 1);// 创建并初始化信号量,表示互斥 
    
	pthread_t bike_frame_thread, bike_wheel_thread, bike_assembler_thread;
    pthread_create(&bike_frame_thread, NULL, bike_frame_worker, NULL);
    pthread_create(&bike_wheel_thread, NULL, bike_wheel_worker, NULL);
    pthread_create(&bike_assembler_thread, NULL, bike_assembler, NULL);

    pthread_join(bike_frame_thread, NULL);
    pthread_join(bike_wheel_thread, NULL);
    pthread_join(bike_assembler_thread, NULL);

    sem_destroy(&bike_frame_sem);
    sem_destroy(&bike_wheel_sem);
    sem_destroy(&product_sem);
	sem_destroy(&box_sem);
	
    return 0;
}

运行过程:

lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ vim main.c
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ gcc main.c -o main -pthread
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ ./main

运行结果
当生产一个车轮和车架所用时间一样,都为1s时,可以看出车轮明显不够用,车架过载
在这里插入图片描述
因此把车轮和车架生产时间改为1:2,就会出现车轮和车架趋于平稳,不会造成挤压。
在这里插入图片描述

2、编写一个用于检查关于命令“ls px ct"的实验报告的Shell脚本,该脚本检查命令的执行结果中是否存在包含“px”和“ct”的文件或目录,显示包含“px”的文件或目录数,包含“ct”的文件或目录数。如果两者的文件或目录数均大于0,则对该实验项目给予100分。如果其中之一的文件或目录数为0,则对该实验项目给予50分,如果两者的文件或目录数均为0,则对该实验项目给予0分。(25分)
源码:]

#!/bin/bash
# 保存输出
output=$(ls *px* *ct* 2>/dev/null)
# 判断是否为空
if [ -z "$output" ]; then
    echo "No files or directories found with 'px' or 'ct' in their names."
    exit 0
fi
# 查询包含px的数量
px_count=$(echo "$output" | grep -c 'px')
# 查询包含ct的数量
ct_count=$(echo "$output" | grep -c 'ct')
# 输出结果
echo "$px_count files/directories found with 'px' in their names."
echo "$ct_count files/directories found with 'ct' in their names."

运行方法:
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ vim findpc.sh
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ chmod +x findpc.sh
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ ./findpc.sh
运行结果:
当一个文件也没有时
结果为:No files or directories found with ‘px’ or ‘ct’ in their names.
在这里插入图片描述

当仅含有px时
结果为:
6 files/directories found with ‘px’ in their names.
0 files/directories found with ‘ct’ in their names.
在这里插入图片描述

当同时含有px和ct时
结果为:
6 files/directories found with ‘px’ in their names.
5 files/directories found with ‘ct’ in their names.

在这里插入图片描述

3、编写套接字通信程序,实现简单的文字发送、接收形式的会议功能。主持人运行服务器程序,参会者运行客户端程序。主持人发送的文字信息每个客户端用户都可以看到。任一客户端用户发送的文字信息包括主持人在内的其他参会者也都可以看到。服务器或者客户端显示当前开会人数,参会者标识,以及当前发送信息的程序或者用户的标识。(50分)

分析过程:
主持人运行服务器程序发给所有客户端,客户运行客户端程序发送给主持人和其它客户端,如果把主持人看作一个特殊的客户,这个问题可以转化为 客户把信息发给中间服务器,中间服务器在发给其它客户。
需要写三个程序,一个是中间服务器,接受主持人和客户的通信,一个是主持人程序,有主持人唯一标识通过中间服务器发给客户,一个客户端程序,信息通过中间服务器发个主持人和客户端。
程序需要用到多线程,服务器端开2个线程,主线程接收套接字,子线程处理客户端发来的信息,把他转发给其它客户端。客户端需要开3个线程,主线程连接服务器,一个线程接受数据,一个线程发送数据。

服务器端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAX_CLIENTS 10
#define BUFFER_SIZE 2048

void * handle_client(void *);

int client_count = 0;

struct Client{
	int client_fd;
	char username[20];	
	char id[20]; 
}client[MAX_CLIENTS];
int main(int argc, char *argv[]) {
    int server_sockfd, client_sockfd;
    struct sockaddr_in server_addr, client_addr;
    pthread_t tid;
    
    if (argc != 2) {
    printf("Usage: %s <port>\n", argv[0]);
    exit(1);
	}
	
	// initialize
    int idx = 0;
    for (idx = 0; idx < MAX_CLIENTS; idx++) {
        client[idx].client_fd = -1;
	}
    
    // initialize server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(atoi(argv[1]));

    // create server socket
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sockfd < 0) {
        perror("Failed to create server socket");
        exit(EXIT_FAILURE);
    }

    // bind the socket to the server address
    if (bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Failed to bind server socket");
        exit(EXIT_FAILURE);
    }

    // listen on the socket for incoming connections
    if (listen(server_sockfd, MAX_CLIENTS) < 0) {
        perror("Failed to listen for incoming connections");
        exit(EXIT_FAILURE);
    }

    printf("Waiting for incoming connections...\n");

    while (1) {
        socklen_t client_addr_size = sizeof(client_addr);
        // accept an incoming connection
        client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_addr_size);
        if (client_sockfd < 0) {
            perror("Failed to accept connection");
            exit(EXIT_FAILURE);
        } 
		
		int i = 0;
		for (idx = 0; idx < MAX_CLIENTS; idx++) {
			if(client[idx].client_fd == -1)
			{
				i = idx;
				break;
			}
		}
		
		client[i].client_fd = client_sockfd; 
        
		printf("Client %d connected\n", i + 1);
    	// get the username from the client
	    
	    
		
		if (recv(client_sockfd, client[i].username, sizeof(client[i].username), 0) <= 0) {
	        perror("Failed to receive username from client");
	        close(client_sockfd);
	        return 0;
	    }
	    
	    // get the id from the client
	    if (recv(client_sockfd, client[i].id, sizeof(client[i].id), 0) <= 0) {
	        perror("Failed to receive id from client");
	        close(client_sockfd);
	        return 0;
	    }
	    
		client_count ++;
        
		// create a new thread to handle the client
        if (pthread_create(&tid, NULL, handle_client, &client_sockfd) != 0) {
            perror("Failed to create thread for client");
            exit(EXIT_FAILURE);
        }

        // detach the thread so it can run in the background
        if (pthread_detach(tid) != 0) {
            perror("Failed to detach thread for client");
            exit(EXIT_FAILURE);
        }
    }

    // close the server socket
    close(server_sockfd);
    return 0;
}

void * handle_client(void *arg) {
    int client_sockfd = *(int*)arg;
    int idx;
    char buffer[BUFFER_SIZE];
	char tmp[BUFFER_SIZE]; 
	char room_number[BUFFER_SIZE];
	char username[20];
	char id[20];
	for (idx = 0; idx < MAX_CLIENTS; idx++) {
        if (client[idx].client_fd == client_sockfd) {
            memcpy(username, client[idx].username,sizeof(client[idx].username));
            memcpy(id, client[idx].id,sizeof(client[idx].id));
			break;
        }
	}
	printf("No.%d Client %s joined the chat\n",idx + 1, username);
	
	// send attebdees number
	sprintf(room_number, "Now, There are %d attendees at the meeting.", client_count);
	for (idx = 0; idx < MAX_CLIENTS; idx++) {
		if(client[idx].client_fd != -1){
			send(client[idx].client_fd, room_number, strlen(room_number), 0);	
		}
    }
	
		
    while (1) {
        // receive message from the client
        int msg_len = recv(client_sockfd, buffer, sizeof(buffer), 0);
        if (msg_len <= 0) {
            printf("Client %s left the chat\n", username);
            break;
        }
        memcpy(tmp, id,sizeof(id));
        strcat(tmp, username);
		strcat(tmp, ": ");
		strcat(tmp, buffer);
		msg_len += strlen(id) + strlen(username) + 2; 
		memcpy(buffer, tmp,sizeof(tmp));
        // forward message to all other clients
        for (idx = 0; idx < MAX_CLIENTS; idx++) {
            if (client[idx].client_fd != -1 && client[idx].client_fd != client_sockfd) {
                send(client[idx].client_fd, buffer, msg_len, 0);
            }
        }
    }

   
    // delete this socket
    for (idx = 0; idx < MAX_CLIENTS; idx++) {
    	if (client[idx].client_fd == client_sockfd) {
            client[idx].client_fd = -1;
        }
	}
	client_count --;
	
	// exit update client_count
	sprintf(room_number, "Now, There are %d attendees at the meeting.", client_count);
	for (idx = 0; idx < MAX_CLIENTS; idx++) {
		if(client[idx].client_fd != -1){
			send(client[idx].client_fd, room_number, strlen(room_number), 0);	
		}
    }
	// close the client socket
    close(client_sockfd);
    return NULL;
}

主持人端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define BUFFER_SIZE 2048

void * send_message(void *);
void * receive_message(void *);

int main(int argc, char *argv[]) {
    int sockfd;
    struct sockaddr_in server_addr;
    char username[20];

    if (argc < 3) {
        printf("Usage: %s <IP address> <port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // initialize server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    server_addr.sin_port = htons(atoi(argv[2]));

    // create socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Failed to create socket");
        exit(EXIT_FAILURE);
    }

    // connect to server
    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Failed to connect to server");
        exit(EXIT_FAILURE);
    }

    // get the username from the user
    printf("Enter your username: ");
    fgets(username, sizeof(username), stdin);
    strtok(username, "\n");
	
	
    // send the username to the server
    if (send(sockfd, username, strlen(username), 0) < 0) {
        perror("Failed to send username to server");
        exit(EXIT_FAILURE);
    }
    
    // send the id to the server
    char id[20] = "<Host>";
    if (send(sockfd, id, strlen(id), 0) < 0) {
        perror("Failed to send id to server");
        exit(EXIT_FAILURE);
    }

    // create threads for sending and receiving messages
    pthread_t send_tid, recv_tid;
    if (pthread_create(&send_tid, NULL, send_message, &sockfd) != 0) {
        perror("Failed to create thread for sending messages");
        exit(EXIT_FAILURE);
    }
    if (pthread_create(&recv_tid, NULL, receive_message, &sockfd) != 0) {
        perror("Failed to create thread for receiving messages");
        exit(EXIT_FAILURE);
    }

    // wait for threads to finish
    pthread_join(send_tid, NULL);
    pthread_join(recv_tid, NULL);

    // close the socket
    close(sockfd);
    return 0;
}

void * send_message(void *arg) {
    int sockfd = *(int*)arg;
    char buffer[BUFFER_SIZE];

    while (1) {
        // read input from the user
        if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
            break;
        }
        buffer[strcspn(buffer, "\n")] = 0; // remove newline character

        // send message to the server
        if (send(sockfd, buffer, strlen(buffer), 0) < 0) {
            perror("Failed to send message to server");
            break;
        }
    }

    // signal the receiving thread to exit
    pthread_cancel(pthread_self());
    return NULL;
}

void * receive_message(void *arg) {
    int sockfd = *(int*)arg;
    char buffer[BUFFER_SIZE];

    while (1) {
        // receive message from the server
        int msg_len = recv(sockfd, buffer, sizeof(buffer), 0);
        if (msg_len <= 0) {
            printf("Disconnected from server\n");
            break;
        }

        // print message to the user
        buffer[msg_len] = '\0';
        printf("%s\n", buffer);
    }

    // signal the sending thread to exit
    pthread_cancel(pthread_self());
    return NULL;
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define BUFFER_SIZE 2048

void * send_message(void *);
void * receive_message(void *);

int main(int argc, char *argv[]) {
    int sockfd;
    struct sockaddr_in server_addr;
    char username[20];

    if (argc < 3) {
        printf("Usage: %s <IP address> <port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // initialize server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    server_addr.sin_port = htons(atoi(argv[2]));

    // create socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Failed to create socket");
        exit(EXIT_FAILURE);
    }

    // connect to server
    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Failed to connect to server");
        exit(EXIT_FAILURE);
    }

    // get the username from the user
    printf("Enter your username: ");
    fgets(username, sizeof(username), stdin);
    strtok(username, "\n");
	
	
    // send the username to the server
    if (send(sockfd, username, strlen(username), 0) < 0) {
        perror("Failed to send username to server");
        exit(EXIT_FAILURE);
    }
    
    // send the id to the server
    char id[20] = "<Attendee>";
    if (send(sockfd, id, strlen(id), 0) < 0) {
        perror("Failed to send id to server");
        exit(EXIT_FAILURE);
    }

    // create threads for sending and receiving messages
    pthread_t send_tid, recv_tid;
    if (pthread_create(&send_tid, NULL, send_message, &sockfd) != 0) {
        perror("Failed to create thread for sending messages");
        exit(EXIT_FAILURE);
    }
    if (pthread_create(&recv_tid, NULL, receive_message, &sockfd) != 0) {
        perror("Failed to create thread for receiving messages");
        exit(EXIT_FAILURE);
    }

    // wait for threads to finish
    pthread_join(send_tid, NULL);
    pthread_join(recv_tid, NULL);

    // close the socket
    close(sockfd);
    return 0;
}

void * send_message(void *arg) {
    int sockfd = *(int*)arg;
    char buffer[BUFFER_SIZE];

    while (1) {
        // read input from the user
        if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
            break;
        }
        buffer[strcspn(buffer, "\n")] = 0; // remove newline character

        // send message to the server
        if (send(sockfd, buffer, strlen(buffer), 0) < 0) {
            perror("Failed to send message to server");
            break;
        }
    }

    // signal the receiving thread to exit
    pthread_cancel(pthread_self());
    return NULL;
}

void * receive_message(void *arg) {
    int sockfd = *(int*)arg;
    char buffer[BUFFER_SIZE];

    while (1) {
        // receive message from the server
        int msg_len = recv(sockfd, buffer, sizeof(buffer), 0);
        if (msg_len <= 0) {
            printf("Disconnected from server\n");
            break;
        }

        // print message to the user
        buffer[msg_len] = '\0';
        printf("%s\n", buffer);
    }

    // signal the sending thread to exit
    pthread_cancel(pthread_self());
    return NULL;
}

运行方法:
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ vim server.c
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ gcc server.c -o server -lpthread
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ ./server 5050

lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ vim client.c
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ gcc client.c -o client -lpthread
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ ./client 121.43.36.60 5005

lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ vim host.c
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ gcc host.c -o host -lpthread
lgy@iZbp16wq7lq85vhufu8oqnZ:~/test$ ./host 121.43.36.60 5005

运行结果:

启动服务器并连接一个主持人和两个客户
在这里插入图片描述

一个主持人和客户连接
在这里插入图片描述

主持人讲话,其它参会者可以看到标识符和主持人名字
在这里插入图片描述

其它参会者讲话,主持人和其它参会者能看到标识符和参会者名字
在这里插入图片描述

新人加入,会更新参加会议总人数
在这里插入图片描述

有人离开会议会更新参会者总人数
在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_WAWA鱼_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值