【Linux操作系统】基于消息队列的银行管理系统<客户端>代码详细分析

这是一个基于信息队列的银行管理系统客户端的项目代码详细讲解,主要介绍了开户、存款、取款等等任务在客户端的运行,代码比较简单,但是每一段代码都进行了详细的讲解,源代码主要来源于:
Linux系统编程阶段项目:基于消息队列的银行管理系统
本文基于其代码进行详细的讲解,也是我拜读其博客之后详细研究后的记录。
在这里插入图片描述



头文件及结构体

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int g_reqid; //作为请求的消息队列的返回id
int g_resid;  //作为应答消息队列的返回id
typedef struct msgbuf{
    
    
    long mtype;         //消息类型
    char id[100];       //账户
    char name[256];     //用户名
    char pw[9];        //密码
    float money;       //银行卡余额
}userm;
typedef struct tag_OpenRespond{
    
    
  long   type;
  char   id[100];      //账户
  char   msg[256];
  float  money;       //银行卡余额
}RES;                 //让客户端从应答消息队列读到的反馈存到这里

主函数

int main()
{
    
    
    while(1)
    {
    
    
        menu();
        int a;
        printf("请输入要执行的操作!\n");
        scanf("%d",&a);
        switch(a)
        {
    
    
            case 1:Account();break;//开户
            case 2:Deposit();break;//存款
            case 3:withdrawal();break;//取款
            case 4:Inquire();break;//查询
            case 5:Transfer();break;//转账
            case 6:Logout();break;//注销
            case 7:
                return 0;

        }
    }
}

主函数非常简单:

  • 主要就是一个循环体while(1)
  • 接着输出一个目录menu()
  • 用户输入一个数值选择要操作的函数;对应的是下面的switch选择语句;
  • 用户输入1的话就是开户,对应的函数为Account()
  • 用户输入2的话就是存款,对应的函数为Deposit()
  • 用户输入3的话就是取款,对应的函数为Withdrawal()
  • 用户输入4的话就是查询,对应的函数为Inquire()
  • 用户输入5的话就是转账,对应的函数为Transfer()
  • 用户输入6的话就是注销,对应的函数为Logout()
  • 用户输入7的话就是退出。

接下来就是一步步解决这些函数的问题:


菜单

void menu()
{
    
    
    printf("*********欢迎来到小黑银行!************\n");
    printf("**************1.开户******************\n");
    printf("**************2.存款******************\n");
    printf("**************3.取款******************\n");
    printf("**************4.查询******************\n");
    printf("**************5.转账******************\n");
    printf("**************6.销户******************\n");
    printf("**************7.退出******************\n");
}

实现菜单功能非常简单,只需要标准输出就行,不需要考虑端口问题,端口让下面的函数实现。


一、开户

void Account()
{
    
    
    key_t kid1,kid2;

    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;//错误提示
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1) 
    {
    
       
        perror("msgget");
        return;
    }   
    
    userm a;
    printf("请输入要注册的身份号!\n");
    scanf("%s",a.id);

    printf("请输入要注册的用户名!\n");
    scanf("%s",a.name);

    printf("请输入要注册的密码!\n");
    scanf("%s",a.pw);

    printf("请输入要注册的余额!\n");
    scanf("%f",&a.money);
    //往请求消息队列写
    a.mtype = 1;   //消息类型为1,开户用
    msgsnd(g_reqid,&a,sizeof(userm)-sizeof(long),0);

    //读应答消息队列
    RES buf;
    msgrcv(g_resid,&buf,sizeof(buf),1,0);  //1类消息,开户用
    printf("%s\n",buf.msg);

    return;

}

代码解释

这段代码是一个C语言函数,用于打开两个消息队列并向其中写入和读取消息。

首先,使用ftok函数生成两个键值,这些键值用于唯一标识消息队列。ftok函数需要传入一个文件路径和一个整数值,它会根据这些参数生成一个唯一的键值。

然后,使用msgget函数打开请求消息队列和应答消息队列。msgget函数接受两个参数,一个是键值,另一个是标志位。IPC_CREAT表示如果消息队列不存在则创建一个新的,0644表示设置权限为读写。

接下来,定义了一个名为userm的结构体变量a,用于存储用户的注册信息。然后通过printfscanf函数分别提示用户输入身份号、用户名、密码和余额,并将用户输入的值存储到结构体变量a的相应字段中。

之后,设置了amtype字段为1,表示这条消息是用于开户的。然后使用msgsnd函数将结构体变量a写入请求消息队列。msgsnd函数接受五个参数,分别是消息队列的ID、指向消息的指针、消息的大小、消息的类型和标志位。这里的消息类型是1,表示开户用。

最后,使用msgrcv函数从应答消息队列中读取消息。msgrcv函数接受五个参数,分别是消息队列的ID、指向消息的指针、消息的大小、消息的类型和标志位。这里的消息类型是1,表示开户用。读取到的消息存储在名为buf的结构体变量中。然后使用printf函数打印出消息的内容。

整个函数的目的是向请求消息队列写入用户的注册信息,并从应答消息队列中读取开户结果并打印出来。


二、存款

void Deposit()//存款业务
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm c;
    printf("请输入要存款用户的身份号!\n");
    scanf("%s",c.id);
   
    printf("请输入要存款用户的用户名!\n");
    scanf("%s",c.name);
    
    printf("请输入要存款用户的密码!\n");
    scanf("%s",c.pw);
   
    printf("请输入要存款的金额!\n");
    scanf("%f",&c.money);
    //往请求消息队列写
    c.mtype = 2;   //消息类型为2,存款用
    msgsnd(g_reqid,&c,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf2;
    msgrcv(g_resid,&buf2,sizeof(buf2),2,0);  //2类消息,存款用
    printf("%s\n",buf2.msg);
    
    return;
}

1. 创建消息队列的键值

key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
  • ftok 函数用于生成一个唯一的键值,作为创建消息队列的标识符。
  • 第一个参数是一个路径名,用于生成键值。
  • 第二个参数是一个整数,用于生成键值。
  • 这里使用两个不同的路径和整数作为参数,生成两个不同的键值。

2. 打开请求消息队列

g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
    
    
    perror("msgget");
    return;
}
  • msgget 函数用于打开或创建一个消息队列。
  • 第一个参数是消息队列的键值。
  • 第二个参数是标志位,IPC_CREAT 表示如果消息队列不存在则创建它,0644 表示设置权限。
  • 函数返回消息队列的标识符,如果返回值为-1,则表示打开或创建失败。

3. 打开应答消息队列

g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
    
    
    perror("msgget");
    return;
}
  • 同样使用 msgget 函数打开或创建一个消息队列,这次使用第二个键值。
  • 如果打开或创建失败,会打印错误信息并返回。

4. 输入存款信息

userm c;
printf("请输入要存款用户的身份号!\n");
scanf("%s",c.id);

printf("请输入要存款用户的用户名!\n");
scanf("%s",c.name);

printf("请输入要存款用户的密码!\n");
scanf("%s",c.pw);

printf("请输入要存款的金额!\n");
scanf("%f",&c.money);
  • 创建一个名为 cuserm 结构体,用于存储用户的相关信息。
  • 依次输入用户的身份号、用户名、密码和存款金额。

5. 将请求写入消息队列

c.mtype = 2;   //消息类型为2,存款用
msgsnd(g_reqid,&c,sizeof(userm)-sizeof(long),0);
  • 将消息类型设置为2,表示这是一个存款请求。
  • 使用 msgsnd 函数将 c 结构体写入请求消息队列。
  • sizeof(userm)-sizeof(long) 表示要发送的消息的大小,减去 long 类型的消息类型字段的大小。

6. 读取应答消息队列

RES buf2;
msgrcv(g_resid,&buf2,sizeof(buf2),2,0);  //2类消息,存款用
printf("%s\n",buf2.msg);
  • 创建一个名为 buf2RES 结构体,用于接收应答消息。
  • 使用 msgrcv 函数从应答消息队列中读取消息。
  • 第一个参数是消息队列的标识符。
  • 第二个参数是接收消息的缓冲区。
  • 第三个参数是接收消息的大小。
  • 第四个参数是消息类型,这里为2,表示接收存款的应答消息。
  • 最后一个参数是标志位,0 表示默认行为。
  • 打印接收到的应答消息。

7. 返回

return;
  • 结束存款业务函数的执行,返回到调用它的地方。

三、取款

void withdrawal()//取款业务
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm d;
    printf("请输入要取款用户的身份号!\n");
    scanf("%s",d.id);
   
    printf("请输入要取款用户的用户名!\n");
    scanf("%s",d.name);
    
    printf("请输入要取款用户的密码!\n");
    scanf("%s",d.pw);
   
    printf("请输入要取款的金额!\n");
    scanf("%f",&d.money);
    //往请求消息队列写
    d.mtype = 3;   //消息类型为3,取款用
    msgsnd(g_reqid,&d,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf3;
    msgrcv(g_resid,&buf3,sizeof(buf3),3,0);  //3类消息,取款用
    printf("%s\n",buf3.msg);
    
    return;
}

1. 创建消息队列的键值

key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
  • ftok 函数用于生成一个唯一的键值,作为创建消息队列的标识符。
  • 第一个参数是一个路径名,用于生成键值。
  • 第二个参数是一个整数,用于生成键值。
  • 这里使用两个不同的路径和整数作为参数,生成两个不同的键值。

2. 打开请求消息队列

g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
    
    
    perror("msgget");
    return;
}
  • msgget 函数用于打开或创建一个消息队列。
  • 第一个参数是消息队列的键值。
  • 第二个参数是标志位,IPC_CREAT 表示如果消息队列不存在则创建它,0644 表示设置权限。
  • 函数返回消息队列的标识符,如果返回值为-1,则表示打开或创建失败。

3. 打开应答消息队列

g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
    
    
    perror("msgget");
    return;
}
  • 同样使用 msgget 函数打开或创建一个消息队列,这次使用第二个键值。
  • 如果打开或创建失败,会打印错误信息并返回。

4. 输入取款信息

userm d;
printf("请输入要取款用户的身份号!\n");
scanf("%s",d.id);

printf("请输入要取款用户的用户名!\n");
scanf("%s",d.name);

printf("请输入要取款用户的密码!\n");
scanf("%s",d.pw);

printf("请输入要取款的金额!\n");
scanf("%f",&d.money);
  • 创建一个名为 duserm 结构体,用于存储用户的相关信息。
  • 依次输入用户的身份号、用户名、密码和取款金额。

5. 将请求写入消息队列

d.mtype = 3;   //消息类型为3,取款用
msgsnd(g_reqid,&d,sizeof(userm)-sizeof(long),0);
  • 将消息类型设置为3,表示这是一个取款请求。
  • 使用 msgsnd 函数将 d 结构体写入请求消息队列。
  • sizeof(userm)-sizeof(long) 表示要发送的消息的大小,减去 long 类型的消息类型字段的大小。

6. 读取应答消息队列

RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),3,0);  //3类消息,取款用
printf("%s\n",buf3.msg);
  • 创建一个名为 buf3RES 结构体,用于接收应答消息。
  • 使用 msgrcv 函数从应答消息队列中读取消息。
  • 第一个参数是消息队列的标识符。
  • 第二个参数是接收消息的缓冲区。
  • 第三个参数是接收消息的大小。
  • 第四个参数是消息类型,这里为3,表示接收取款的应答消息。
  • 最后一个参数是标志位,0 表示默认行为。
  • 打印接收到的应答消息。

7. 返回

return;
  • 结束取款业务函数的执行,返回到调用它的地方。

四、查询

void Inquire()//查询业务
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm e;
    printf("请输入要查询用户的身份号!\n");
    scanf("%s",e.id);
   
    printf("请输入要查询用户的用户名!\n");
    scanf("%s",e.name);
    
    printf("请输入要查询用户的密码!\n");
    scanf("%s",e.pw);
   
    //printf("请输入要查询的金额!\n");
    //scanf("%f",&d.money);
    //往请求消息队列写
    e.mtype = 4;   //消息类型为4,查询用
    msgsnd(g_reqid,&e,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf4;
    msgrcv(g_resid,&buf4,sizeof(buf4),4,0);  //消息类型为4,查询用
    printf("%s\n",buf4.msg);
    
    return;
}

1. 创建消息队列的键值

key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
  • 同样使用 ftok 函数生成两个不同的键值,用于创建消息队列。

2. 打开请求消息队列

g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
    
    
    perror("msgget");
    return;
}
  • 使用 msgget 函数打开或创建请求消息队列。

3. 打开应答消息队列

g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
    
    
    perror("msgget");
    return;
}
  • 同样使用 msgget 函数打开或创建应答消息队列。

4. 输入查询信息

userm e;
printf("请输入要查询用户的身份号!\n");
scanf("%s",e.id);

printf("请输入要查询用户的用户名!\n");
scanf("%s",e.name);

printf("请输入要查询用户的密码!\n");
scanf("%s",e.pw);
  • 创建一个名为 euserm 结构体,用于存储查询用户的相关信息。
  • 依次输入用户的身份号、用户名和密码。

5. 将请求写入消息队列

e.mtype = 4;   //消息类型为4,查询用
msgsnd(g_reqid,&e,sizeof(userm)-sizeof(long),0);
  • 将消息类型设置为4,表示这是一个查询请求。
  • 使用 msgsnd 函数将 e 结构体写入请求消息队列。
  • sizeof(userm)-sizeof(long) 表示要发送的消息的大小,减去 long 类型的消息类型字段的大小。

6. 读取应答消息队列

RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),4,0);  //消息类型为4,查询用
printf("%s\n",buf4.msg);
  • 创建一个名为 buf4RES 结构体,用于接收应答消息。
  • 使用 msgrcv 函数从应答消息队列中读取消息。
  • 第一个参数是消息队列的标识符。
  • 第二个参数是接收消息的缓冲区。
  • 第三个参数是接收消息的大小。
  • 第四个参数是消息类型,这里为4,表示接收查询的应答消息。
  • 最后一个参数是标志位,0 表示默认行为。
  • 打印接收到的应答消息。

7. 返回

return;
  • 结束查询业务函数的执行,返回到调用它的地方。

五、转账

void Transfer()//转账业务
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm f1,f2;
    printf("请输入转账用户的身份号!\n");
    scanf("%s",f1.id);
   
    printf("请输入转账用户的用户名!\n");
    scanf("%s",f1.name);
    
    printf("请输入转账用户的密码!\n");
    scanf("%s",f1.pw);
   
    printf("请输入要转账的金额!\n");
    scanf("%f",&f1.money);
    
    printf("请输入被转账用户的身份号!\n");
    scanf("%s",f2.id);
    //往请求消息队列写
    f1.mtype = 5;   //消息类型为5,转账用,第一条消息,转账用户用
    msgsnd(g_reqid,&f1,sizeof(userm)-sizeof(long),0);
    f2.mtype = 55;   //消息类型为55,转账用,第二条消息,被转账用户用
    msgsnd(g_reqid,&f2,sizeof(userm)-sizeof(long),0);
    //读应答消息队列
    RES buf3;
    msgrcv(g_resid,&buf3,sizeof(buf3),5,0);  //5类消息,转账用
    printf("%s\n",buf3.msg);
    
    
    RES buf4;
    msgrcv(g_resid,&buf4,sizeof(buf4),55,0);  //55类消息,转账用
    printf("%s\n",buf4.msg);
    return;
}

1. 创建消息队列的键值

key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
  • 同样使用 ftok 函数生成两个不同的键值,用于创建消息队列。

2. 打开请求消息队列

g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
    
    
    perror("msgget");
    return;
}
  • 使用 msgget 函数打开或创建请求消息队列。

3. 打开应答消息队列

g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
    
    
    perror("msgget");
    return;
}
  • 同样使用 msgget 函数打开或创建应答消息队列。

4. 输入转账用户信息

userm f1,f2;
printf("请输入转账用户的身份号!\n");
scanf("%s",f1.id);

printf("请输入转账用户的用户名!\n");
scanf("%s",f1.name);

printf("请输入转账用户的密码!\n");
scanf("%s",f1.pw);

printf("请输入要转账的金额!\n");
scanf("%f",&f1.money);
  • 创建两个名为 f1f2userm 结构体,分别用于存储转账用户和被转账用户的相关信息。
  • 依次输入转账用户的身份号、用户名、密码和转账金额。

5. 将请求写入消息队列

f1.mtype = 5;   //消息类型为5,转账用,第一条消息,转账用户用
msgsnd(g_reqid,&f1,sizeof(userm)-sizeof(long),0);
f2.mtype = 55;   //消息类型为55,转账用,第二条消息,被转账用户用
msgsnd(g_reqid,&f2,sizeof(userm)-sizeof(long),0);
  • 将消息类型设置为5和55,表示这是转账请求的两条消息。
  • 使用 msgsnd 函数将 f1f2 结构体分别写入请求消息队列。
  • sizeof(userm)-sizeof(long) 表示要发送的消息的大小,减去 long 类型的消息类型字段的大小。

6. 读取应答消息队列

RES buf3;
msgrcv(g_resid,&buf3,sizeof(buf3),5,0);  //5类消息,转账用
printf("%s\n",buf3.msg);


RES buf4;
msgrcv(g_resid,&buf4,sizeof(buf4),55,0);  //55类消息,转账用
printf("%s\n",buf4.msg);
  • 创建两个名为 buf3buf4RES 结构体,用于接收应答消息。
  • 使用 msgrcv 函数从应答消息队列中读取消息。
  • 第一个参数是消息队列的标识符。
  • 第二个参数是接收消息的缓冲区。
  • 第三个参数是接收消息的大小。
  • 第四个参数是消息类型,这里分别为5和55,表示接收转账的应答消息。
  • 最后一个参数是标志位,0 表示默认行为。
  • 打印接收到的应答消息。

7. 返回

return;
  • 结束转账业务函数的执行,返回到调用它的地方。

六、注销

void Logout()
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm b;
    printf("请输入要注销用户的身份号!\n");
    scanf("%s",b.id);
   
    printf("请输入要注销用户的用户名!\n");
    scanf("%s",b.name);
    
    printf("请输入要注销用户的密码!\n");
    scanf("%s",b.pw);
   
    printf("请输入要注销用户的余额!\n");
    scanf("%f",&b.money);
    //往请求消息队列写
    b.mtype = 6;   //消息类型为6,注销用
    msgsnd(g_reqid,&b,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf1;
    msgrcv(g_resid,&buf1,sizeof(buf1),6,0);  //6类消息,注销用
    printf("%s\n",buf1.msg);
    
    return;
}

1. 创建消息队列的键值

key_t kid1,kid2;
kid1 = ftok("/home/whs/002/0706",1); //键值
kid2 = ftok("/home/whs/002/0706",2);
  • 同样使用 ftok 函数生成两个不同的键值,用于创建消息队列。

2. 打开请求消息队列

g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
if(g_reqid== -1)
{
    
    
    perror("msgget");
    return;
}
  • 使用 msgget 函数打开或创建请求消息队列。

3. 打开应答消息队列

g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
if(g_resid == -1)
{
    
    
    perror("msgget");
    return;
}
  • 同样使用 msgget 函数打开或创建应答消息队列。

4. 输入注销用户信息

userm b;
printf("请输入要注销用户的身份号!\n");
scanf("%s",b.id);

printf("请输入要注销用户的用户名!\n");
scanf("%s",b.name);

printf("请输入要注销用户的密码!\n");
scanf("%s",b.pw);

printf("请输入要注销用户的余额!\n");
scanf("%f",&b.money);
  • 创建名为 buserm 结构体,用于存储注销用户的相关信息。
  • 依次输入要注销用户的身份号、用户名、密码和余额。

5. 将请求写入消息队列

b.mtype = 6;   //消息类型为6,注销用
msgsnd(g_reqid,&b,sizeof(userm)-sizeof(long),0);
  • 将消息类型设置为6,表示这是注销请求的消息。
  • 使用 msgsnd 函数将 b 结构体写入请求消息队列。
  • sizeof(userm)-sizeof(long) 表示要发送的消息的大小,减去 long 类型的消息类型字段的大小。

6. 读取应答消息队列

RES buf1;
msgrcv(g_resid,&buf1,sizeof(buf1),6,0);  //6类消息,注销用
printf("%s\n",buf1.msg);
  • 创建名为 buf1RES 结构体,用于接收应答消息。
  • 使用 msgrcv 函数从应答消息队列中读取消息。
  • 第一个参数是消息队列的标识符。
  • 第二个参数是接收消息的缓冲区。
  • 第三个参数是接收消息的大小。
  • 第四个参数是消息类型,这里为6,表示接收注销的应答消息。
  • 最后一个参数是标志位,0 表示默认行为。
  • 打印接收到的应答消息。

7. 返回

return;
  • 结束注销用户业务函数的执行,返回到调用它的地方。

整体代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int g_reqid; //作为请求的消息队列的返回id
int g_resid;  //作为应答消息队列的返回id
typedef struct msgbuf{
    
    
    long mtype;         //消息类型
    char id[100];       //账户
    char name[256];     //用户名
    char pw[9];        //密码
    float money;       //银行卡余额
}userm;
typedef struct tag_OpenRespond{
    
    
  long   type;
  char   id[100];      //账户
  char   msg[256];
  float  money;       //银行卡余额
}RES;                 //让客户端从应答消息队列读到的反馈存到这里
void menu();
void Account();//开户
void Deposit();//存款
void withdrawal();//取款
void Inquire();//查询
void Transfer();//转账
void Logout();//注销
int main()
{
    
    
    while(1)
    {
    
    
        menu();
        int a;
        printf("请输入要执行的操作!\n");
        scanf("%d",&a);
        switch(a)
          {
    
    
            case 1:Account();break;//开户
            case 2:Deposit();break;//存款
            case 3:withdrawal();break;//取款
            case 4:Inquire();break;//查询
            case 5:Transfer();break;//转账
            case 6:Logout();break;//注销
            case 7:
                return 0;
            
        }
    }
}
void Account()
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    
    userm a;
    printf("请输入要注册的身份号!\n");
    scanf("%s",a.id);
   
    printf("请输入要注册的用户名!\n");
    scanf("%s",a.name);
    
    printf("请输入要注册的密码!\n");
    scanf("%s",a.pw);
   
    printf("请输入要注册的余额!\n");
    scanf("%f",&a.money);
    //往请求消息队列写
    a.mtype = 1;   //消息类型为1,开户用
    msgsnd(g_reqid,&a,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf;
    msgrcv(g_resid,&buf,sizeof(buf),1,0);  //1类消息,开户用
    printf("%s\n",buf.msg);
    
    return;
    
}
void Logout()
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm b;
    printf("请输入要注销用户的身份号!\n");
    scanf("%s",b.id);
   
    printf("请输入要注销用户的用户名!\n");
    scanf("%s",b.name);
    
    printf("请输入要注销用户的密码!\n");
    scanf("%s",b.pw);
   
    printf("请输入要注销用户的余额!\n");
    scanf("%f",&b.money);
    //往请求消息队列写
    b.mtype = 6;   //消息类型为6,注销用
    msgsnd(g_reqid,&b,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf1;
    msgrcv(g_resid,&buf1,sizeof(buf1),6,0);  //6类消息,注销用
    printf("%s\n",buf1.msg);
    
    return;
}
void Deposit()//存款业务
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm c;
    printf("请输入要存款用户的身份号!\n");
    scanf("%s",c.id);
   
    printf("请输入要存款用户的用户名!\n");
    scanf("%s",c.name);
    
    printf("请输入要存款用户的密码!\n");
    scanf("%s",c.pw);
   
    printf("请输入要存款的金额!\n");
    scanf("%f",&c.money);
    //往请求消息队列写
    c.mtype = 2;   //消息类型为2,存款用
    msgsnd(g_reqid,&c,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf2;
    msgrcv(g_resid,&buf2,sizeof(buf2),2,0);  //2类消息,存款用
    printf("%s\n",buf2.msg);
    
    return;
}
void withdrawal()//取款业务
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm d;
    printf("请输入要取款用户的身份号!\n");
    scanf("%s",d.id);
   
    printf("请输入要取款用户的用户名!\n");
    scanf("%s",d.name);
    
    printf("请输入要取款用户的密码!\n");
    scanf("%s",d.pw);
   
    printf("请输入要取款的金额!\n");
    scanf("%f",&d.money);
    //往请求消息队列写
    d.mtype = 3;   //消息类型为3,取款用
    msgsnd(g_reqid,&d,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf3;
    msgrcv(g_resid,&buf3,sizeof(buf3),3,0);  //3类消息,取款用
    printf("%s\n",buf3.msg);
    
    return;
}
void Inquire()
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm e;
    printf("请输入要查询用户的身份号!\n");
    scanf("%s",e.id);
   
    printf("请输入要查询用户的用户名!\n");
    scanf("%s",e.name);
    
    printf("请输入要查询用户的密码!\n");
    scanf("%s",e.pw);
   
    //printf("请输入要查询的金额!\n");
    //scanf("%f",&d.money);
    //往请求消息队列写
    e.mtype = 4;   //消息类型为4,查询用
    msgsnd(g_reqid,&e,sizeof(userm)-sizeof(long),0);
    
    //读应答消息队列
    RES buf4;
    msgrcv(g_resid,&buf4,sizeof(buf4),4,0);  //消息类型为4,查询用
    printf("%s\n",buf4.msg);
    
    return;
}
void Transfer()//转账业务
{
    
    
    key_t kid1,kid2;
   
    kid1 = ftok("/home/whs/002/0706",1); //键值
    kid2 = ftok("/home/whs/002/0706",2);
    g_reqid = msgget(kid1,IPC_CREAT|0644); //打开请求消息队列
    if(g_reqid== -1)
    {
    
    
        perror("msgget");
        return;
    }
 
    g_resid =msgget(kid2,IPC_CREAT|0644); //打开应答消息队列
    if(g_resid == -1)
    {
    
    
        perror("msgget");
        return;
    }
    userm f1,f2;
    printf("请输入转账用户的身份号!\n");
    scanf("%s",f1.id);
   
    printf("请输入转账用户的用户名!\n");
    scanf("%s",f1.name);
    
    printf("请输入转账用户的密码!\n");
    scanf("%s",f1.pw);
   
    printf("请输入要转账的金额!\n");
    scanf("%f",&f1.money);
    
    printf("请输入被转账用户的身份号!\n");
    scanf("%s",f2.id);
    //往请求消息队列写
    f1.mtype = 5;   //消息类型为5,转账用,第一条消息,转账用户用
    msgsnd(g_reqid,&f1,sizeof(userm)-sizeof(long),0);
    f2.mtype = 55;   //消息类型为55,转账用,第二条消息,被转账用户用
    msgsnd(g_reqid,&f2,sizeof(userm)-sizeof(long),0);
    //读应答消息队列
    RES buf3;
    msgrcv(g_resid,&buf3,sizeof(buf3),5,0);  //5类消息,转账用
    printf("%s\n",buf3.msg);
    
    
    RES buf4;
    msgrcv(g_resid,&buf4,sizeof(buf4),55,0);  //55类消息,转账用
    printf("%s\n",buf4.msg);
    return;
}
void menu()
{
    
    
    printf("********欢迎来到小黑银行!************\n");
    printf("**************1.开户******************\n");
    printf("**************2.存款******************\n");
    printf("**************3.取款******************\n");
    printf("**************4.查询******************\n");
    printf("**************5.转账******************\n");
    printf("**************6.销户******************\n");
    printf("**************7.退出******************\n");
    
}

猜你喜欢

转载自blog.csdn.net/Goforyouqp/article/details/132892369
今日推荐