④ 模拟C/S通信,要求如下: a.模拟客户端(Client端)程序client,其功能是: 1.显示下列服务功能菜单: ************************** * 1:Query balance * * 2:Draw money * * 3:Save money * * 4:Change password * * 0:Exit * ************************* * 2.接收用户键入的功能号选择; 3.将用户键入的功能号作为一条信息发送到消息队列,然后结束。 b.模拟服务器端(Server端)程序server,其功能是: 1.从消息队列接收Client端发来的一条消息; 2.父进程创建一个子进程; 3.根据消息作如下处理: 若消息为"1",子进程1加载服务模块query,该模块的内容为显示以下信息:You have $10000! 若消息为"2",子进程1加载服务模块draw,该模块的内容为显示以下信息:You have drawn $10000! 若消息为"3",子进程1加载服务模块save,该模块的内容为显示以下信息:You have saved $10000! 若消息为"4",子进程1加载服务模块change,该模块的内容为显示以下信息:Your password has changed! 若消息为"0",退出子进程。 4.等待子进程终止后,Server进程删除消息缓冲队列,然后结束。 注意: I).各个子模块query、draw、save和change要事先编译连接好,放在你认为合适的子目录下; II).采用先运行客户端进程,然后运行服务器端进程的方式实现同步; III).注意子进程的加载方法 在linux系统下,根据要求给出代码要求
时间: 2023-06-29 15:14:32 浏览: 114
好的,以下是模拟C/S通信的客户端和服务器端程序的代码实现:
客户端程序 client.c:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MSG_TYPE 1
struct msgbuf {
long mtype;
int func_num;
};
int main() {
int running = 1;
int msgid;
struct msgbuf data;
// 创建消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed\n");
exit(EXIT_FAILURE);
}
// 显示服务功能菜单
printf("**************************\n");
printf("* 1:Query balance *\n");
printf("* 2:Draw money *\n");
printf("* 3:Save money *\n");
printf("* 4:Change password *\n");
printf("* 0:Exit *\n");
printf("**************************\n");
// 接收用户键入的功能号选择
while (running) {
printf("\nEnter function number: ");
scanf("%d", &data.func_num);
getchar(); // 消耗回车符
// 将用户键入的功能号作为一条信息发送到消息队列
data.mtype = MSG_TYPE;
if (msgsnd(msgid, (void *)&data, sizeof(int), 0) == -1) {
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if (data.func_num == 0) {
running = 0;
}
}
// 结束客户端程序
exit(EXIT_SUCCESS);
}
```
服务器端程序 server.c:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#define MSG_TYPE 1
struct msgbuf {
long mtype;
int func_num;
};
void query() {
printf("You have $10000!\n");
exit(EXIT_SUCCESS);
}
void draw() {
printf("You have drawn $10000!\n");
exit(EXIT_SUCCESS);
}
void save() {
printf("You have saved $10000!\n");
exit(EXIT_SUCCESS);
}
void change() {
printf("Your password has changed!\n");
exit(EXIT_SUCCESS);
}
int main() {
int msgid, pid, status;
struct msgbuf data;
// 创建消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed\n");
exit(EXIT_FAILURE);
}
while (1) {
// 从消息队列接收消息
if (msgrcv(msgid, (void *)&data, sizeof(int), MSG_TYPE, 0) == -1) {
fprintf(stderr, "msgrcv failed\n");
exit(EXIT_FAILURE);
}
// 父进程创建一个子进程
pid = fork();
if (pid == -1) {
fprintf(stderr, "fork failed\n");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程根据消息作如下处理
switch (data.func_num) {
case 1:
query();
break;
case 2:
draw();
break;
case 3:
save();
break;
case 4:
change();
break;
case 0:
exit(EXIT_SUCCESS);
default:
fprintf(stderr, "invalid function number\n");
exit(EXIT_FAILURE);
}
} else {
// 等待子进程终止
wait(&status);
}
}
// 删除消息缓冲队列
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl failed\n");
exit(EXIT_FAILURE);
}
// 结束服务器端程序
exit(EXIT_SUCCESS);
}
```
注意,上述代码中的服务模块 query、draw、save 和 change 需要先编译连接好,放在一个子目录下。在上述代码中,我们假设这些服务模块已经编译连接好,并且放在了子目录 services 下面。
编译命令:
```
gcc -o client client.c
gcc -o server server.c
gcc -o services/query services/query.c
gcc -o services/draw services/draw.c
gcc -o services/save services/save.c
gcc -o services/change services/change.c
```
运行程序:
```
./client
./server
```
注意,先运行客户端程序,等待用户键入功能号后再发送消息到消息队列;服务器端程序需要在客户端程序发送消息之后才能运行,接收消息并进行处理。
阅读全文