Linux服务器搭建 前后置服务器通信技术

目录

一:前后置服务器通信

二:共享内存共用设计

三:共享内存 + 消息队列 + 信号量  模拟前后置服务器通信


一:前后置服务器通信

前后置服务器通信可以大致看作是进程间通信,使用到IPC技术,包括有共享内存+消息队列+信号量

大致设计是

前置服务器将数据写入共享内存,且发送消息队列通知后置服务器及时读取处理数据返回

后置服务器需要先读索引区1才可以读取共享内存数据区,读数据区数据后需要清空数据区

前置服务器使用信号量(进程锁机制),确保将数据写入之后,后置服务器才能读取数据

共享内存共用设计:索引区 + 数据区

二:共享内存共用设计

本节工程分为写工程(模拟前置服务器)+读工程(模拟后置服务器),

前后置服务器通信 使用IPC技术有:共享内存共用+发送消息队列+信号量进程锁机制

下面对数据通信结果做个测试,在测试前注意先操作系统初始化内存三剑客:ipcrm -a

确保消息队列、共享内存、信号量初始化,可检测是否为初始状态:ipcs

检查无误后,首先运行的是写数据工程,

如果只写不读,那么数组会开50个空间 ,(共享内存共用,还没被读的数据是占用空间的)

不过由于测试的时间太长,这里以写15个数据后开始读操作为例

在写入15个数据后,开始读数据,

不难看出,每写完15个数据后(且读取完15个数据后),找到可以写数据的下标从15又回到了数组下标0再写数据(共享内存共用数据再读取后能够重新根据索引区标志位再次写入数据至数据区) 

在测试之后,可以 ipcs 查看一下内存三剑客 目前的状态

可以看到消息17条(测试是在17条数据写入读取后 关闭了写、读工程)

三:共享内存 + 消息队列 + 信号量  模拟前后置服务器通信

读工程(模拟后置服务器操作) 

#include<iostream>
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include<unistd.h>
#include<string.h>

//数据块大小
#define BLOCKNUM 50

using namespace std;

union semun {
	int              val;    /* Value for SETVAL */
	struct semid_ds* buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short* array;  /* Array for GETALL, SETALL */
	struct seminfo* __buf;  /* Buffer for IPC_INFO
								(Linux-specific) */
};

typedef struct msgsendbuf {
	long mtype;       /* message type, must be > 0 */
	char mtext[2];    /* message data */
}MSGBUF;

typedef struct student
{
	char stuid[20];
	char stuname[20];
}STU;

//信号量的创建
int sem_create(key_t key, int num_sems)
{
	int res = 0;
	res = semget(key, num_sems, IPC_CREAT | 0777);
	if (res < 0)
	{
		perror("semget error");
	}
	return res;
}

//信号量赋初始值
int sem_setVal(int semid, int semindex, int val)
{
	union semun arg;
	arg.val = val;

	int res = semctl(semid, semindex, SETVAL, arg);
	if (res < 0)
	{
		perror("semctl error");
	}
	return res;
}

//信号量 P操作 -1
int sem_p(int sem_id, int semindex)
{
	struct sembuf buf = { semindex,-1,SEM_UNDO };
	int res = semop(sem_id, &buf, 1);
	if (res < 0)
	{
		perror("semop error");
	}
	return res;
}

//信号量 V操作 +1
int sem_v(int sem_id, int semindex)
{
	struct sembuf buf = { semindex,1,SEM_UNDO };
	int res = semop(sem_id, &buf, 1);
	if (res < 0)
	{
		perror("semop error");
	}
	return res;
}

int main()
{
	void* shmaddr; //共享内存首地址
	int shmid = 0; //共享内存id
	int msgid = 0; //消息队列id
	MSGBUF sendbuf = { 0 }; //消息队列发送信息的结构体
	int semid = 0; //信号量id
	int arr[BLOCKNUM] = { 0 }; //数组
	int index = 0; //数组下标

	int num = 1;

	STU stu1 = { "","陈茹涵"};

	//共享内存创建
	shmid = shmget((key_t)1001, sizeof(arr) + sizeof(STU) * BLOCKNUM, IPC_CREAT | 0777);
	if (shmid < 0)
	{
		perror("shmid error");
	}
	//消息队列
	msgid = msgget((key_t)1002, IPC_CREAT | 0777);
	if(msgid < 0)
	{
		perror("msgid error");
	}
	//信号量创建
	semid = sem_create((key_t)1003, 1);
	if (semid < 0)
	{
		perror("sem_create error");
	}
	else
	{
		//信号量0下标设置初始值1
		sem_setVal(semid, 0, 1);
	}

	while (1)
	{
		cout << "------------------准备工作完成 开始写数据--------------------" << endl;
		//进程加锁
		sem_p(semid, 0);

		//操作共享内存先连接 获取共享内存首地址
		shmaddr = shmat(shmid, NULL, 0);

		//读索引区
		memcpy(arr, shmaddr, sizeof(arr));

		for (int i = 0; i < BLOCKNUM; i++)
		{
			if (arr[i] == 0)
			{
				index = i;
				break;
			}
		}
		cout << "找到可以写数据的下标 index =" << index << endl;

		sprintf(stu1.stuid, "OMO22030%d", num);

		//1 写数据区
		memcpy((void*)(shmaddr + sizeof(arr) + index * sizeof(STU)), &stu1, sizeof(STU));
		//2 写索引区
		arr[index] = 1;
		memcpy((void*)(shmaddr + index * sizeof(int)), &arr[index], sizeof(int));

		//共享内存的断开连接
		shmdt(shmaddr);

		//进程解锁
		sem_v(semid, 0);
		cout << "共享内存写入成功" << endl;

		//消息队列通知后置服务器
		sendbuf.mtype = 1;
		sprintf(sendbuf.mtext, "%d", index);

		if (msgsnd(msgid, &sendbuf, sizeof(sendbuf), 0) == -1)
		{
			perror("msgsnd error");
		}
		cout << "消息队列发送成功" << endl;

		index = 0;
		bzero(&sendbuf, sizeof(sendbuf));
		bzero(&arr, sizeof(arr));
		num++;

		sleep(1);
	}
	return 0;
}

写工程(模拟前置服务器操作) 

#include<iostream>
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

//数据块大小
#define BLOCKNUM 50

using namespace std;

union semun {
	int              val;    /* Value for SETVAL */
	struct semid_ds* buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short* array;  /* Array for GETALL, SETALL */
	struct seminfo* __buf;  /* Buffer for IPC_INFO
								(Linux-specific) */
};

typedef struct msgsendbuf {
	long mtype;       /* message type, must be > 0 */
	char mtext[2];    /* message data */
}MSGBUF;

typedef struct student
{
	char stuid[20];
	char stuname[20];
}STU;

//信号量的创建
int sem_create(key_t key, int num_sems)
{
	int res = 0;
	res = semget(key, num_sems, IPC_CREAT | 0777);
	if (res < 0)
	{
		perror("semget error");
	}
	return res;
}



//信号量 P操作 -1
int sem_p(int sem_id, int semindex)
{
	struct sembuf buf = { semindex,-1,SEM_UNDO };
	int res = semop(sem_id, &buf, 1);
	if (res < 0)
	{
		perror("semop error");
	}
	return res;
}

//信号量 V操作 +1
int sem_v(int sem_id, int semindex)
{
	struct sembuf buf = { semindex,1,SEM_UNDO };
	int res = semop(sem_id, &buf, 1);
	if (res < 0)
	{
		perror("semop error");
	}
	return res;
}

int main()
{
	void* shmaddr; //共享内存首地址
	int shmid = 0; //共享内存id
	int msgid = 0; //消息队列id
	MSGBUF rcvbuf = { 0 }; //消息队列接收信息的结构体
	int semid = 0; //信号量id
	int arr[BLOCKNUM] = { 0 }; //数组
	int index = 0; //数组下标

	STU resstu = { 0 };

	//共享内存创建
	shmid = shmget((key_t)1001, sizeof(arr) + sizeof(STU) * BLOCKNUM, IPC_CREAT | 0777);
	if (shmid < 0)
	{
		perror("shmid error");
	}
	//消息队列
	msgid = msgget((key_t)1002, IPC_CREAT | 0777);
	if (msgid < 0)
	{
		perror("msgid error");
	}
	//信号量创建
	semid = sem_create((key_t)1003, 1);
	if (semid < 0)
	{
		perror("sem_create error");
	}

	while (1)
	{
		cout << "------------------准备工作完成 开始读数据--------------------" << endl;

		if (msgrcv(msgid, &rcvbuf, sizeof(rcvbuf), 1, 0) == -1)
		{
			perror("msgrcv error");
		}
		else
		{
			index = atoi(rcvbuf.mtext);
			cout << "读到的数据的下标 index =" << index << endl;
			sem_p(semid, 0);
			shmaddr = shmat(shmid, NULL, 0);

			//1 先读索引区 index下标的位置
			memcpy(&arr[index], (void*)(shmaddr + index * sizeof(int)), sizeof(int));
			//判断是否为1 为1 表示可以读取
			if (arr[index] == 1)
			{
				//2 读取数据区数据
				memcpy(&resstu, (void*)(shmaddr + sizeof(arr) + index * sizeof(STU)), sizeof(STU));
				//3 清空数据区
				memset((void*)(shmaddr + sizeof(arr) + index * sizeof(STU)), 0, sizeof(STU));
				//4 索引区 对应下标位置修改0 这里操作arr是进程中的数组,并不是共享内存的数组
				//因此 再写入一次共享内存索引区
				arr[index] = 0;
				memcpy((void*)(shmaddr + sizeof(int) * index), &arr[index], sizeof(int));
				cout << "读到的数据 resstu.stuid = " << resstu.stuid << endl;
				cout << "读到的数据 resstu.stuname = " << resstu.stuname << endl;
				cout << "读数据完成" << endl;
			}

			shmdt(shmaddr);
			sem_v(semid, 0);
		}
		
		index = 0;
		bzero(&rcvbuf, sizeof(rcvbuf));
		bzero(&arr, sizeof(arr));

		sleep(1);
	}
	return 0;
}
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

chenruhan_QAQ_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值