进程共享技术-管道

进程通信:一个进程不能读写另一个进程的内存,所以这儿要使用进程通信。

操作系统中,一个进程不能读写(访问)另一个进程的内存空间,进程的内存空间使用是各自独立的。但C语言有个特点,即C语言可以把所有的设备都当做一个“文件”来操作。C语言可以把一片内存空间当作一个设备,即文件来操作,这时别的进程也可以读取这片内存空间,从而达到数据共享,进程通信的目底。

进程通信有下图所示的几种方式:


下面代码实现了多线程的管道通信:

客户端随生成二个随机数,连接到管道并把随机数发给服务器,服务从管道中获得数据计算好后把结果返还给客户端,而服务器端开了多线程可以提供多任务处理功能,客户端的代码如下:


#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Windows.h>
#include<time.h>
#define SIZE 4096	//管道大小
char pipename[128] = "\\\\.\\pipe\\test";		//以设备命名,注意命名书写方式  管道分匿名和命名管道
HANDLE m_pipe = NULL;	//命名管道的句柄	

int a;
int b;

//生成二个随机数,在云端计算
void run()
{
	time_t ts;
	unsigned int num = time(&ts);
	srand(num);
	a = rand() % 1000;
	b = rand() % 1000;

}

void main()
{
	printf("连接服务器...\n");
	m_pipe = CreateFileA(pipename,//名称
		GENERIC_WRITE | GENERIC_READ,		//读写
		0,		//1:不共享属性 0:共享,并发
		NULL,		//默认安全属性
		OPEN_EXISTING,		//打开已经存在的
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (m_pipe == INVALID_HANDLE_VALUE)
	{
		printf("打开失败!\n");
		return;
	}
	int nwrite = 0;
	int nread = 0;
	run();
	char winfo[1024] = { 0 };
	sprintf(winfo, "%d %d", a, b);		//打印数据进去
	WriteFile(m_pipe, winfo, strlen(winfo), &nwrite, NULL);//	写入
	
	//因为又要读出,所以把这片区域清零
	memset(winfo, 0, sizeof(winfo));	
	ReadFile(m_pipe,winfo,1024,&nread, NULL);

	int res;
	sscanf(winfo, "%d", &res);	//从字符串中扫描出来数据
	printf("\n%d+%d=%d\n", a, b, res);

	system("pause");
}

下面是服务器端,服务器从管道中获取客户写入的数据,计算出结果后再写入管道,因为服务器开了多线程,所以可以同时处理多个客户端的请求,这也是云计算的模型,这个也可以称为云端服务器。


/*
	一个客户请求我们就创建一个线程进行响应。
	如果总是阻塞就没办发实现并发处理多客户请求。
	所以我们这儿就使用多线程来处理。
*/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Windows.h>

#define SIZE 4096	//管道大小
#define MAX_CONNECT 128		//最大的链接
int startthreadnum = 10;	//一开始开辟10个线程
char pipename[128] = "\\\\.\\pipe\\test";		//以设备命名,注意命名书写方式  管道分匿名和命名管道


typedef struct info
{
	int id;
	HANDLE hthread;		//线程
	HANDLE hpipe;		//管道,一个线程必须要有一个管道
	HANDLE hevent;		//需要使用消息机制,发一条消息
}PIPE_ST;
PIPE_ST pipeist[MAX_CONNECT];	//128个结构体,即最大128个线程

//线程
DWORD WINAPI severThread(void *p)
{
	
	DWORD nread = 0;
	DWORD nwrite = 0;
	DWORD dwbyte = 0;	//
	char szbuf[SIZE] = { 0 };
	PIPE_ST curpipe = *(PIPE_ST*)p;		//获取当前结构体
	OVERLAPPED overlap = {0,0,0,0,curpipe.hevent};		//初始化结构体
	
	//处理数据
	while (1)
	{
		memset(szbuf, 0, sizeof(szbuf));
		ConnectNamedPipe(curpipe.hpipe, &overlap);		//链接管道,把信息写到结构体
		WaitForSingleObject(curpipe.hevent, INFINITE);		//等待事件
		printf("%d:线程开始处理...\n",curpipe.id);
		//需要做二个判断 1:什么时间跳出循环
		//检测 I/0,如果完成就跳出
		if (!GetOverlappedResult(curpipe.hpipe, &overlap, &dwbyte, TRUE))	
		{
			break;
		}
		if (!ReadFile(curpipe.hpipe, szbuf, SIZE, &nread, NULL))
		{
			puts("read fail");
			break;
		}
		int a, b;
		sscanf(szbuf, "%d %d", &a, &b);
		memset(szbuf, 0, sizeof(szbuf));		//清零
		sprintf(szbuf, "%d", a + b);	//打印到szbuf中
		WriteFile(curpipe.hpipe,szbuf,strlen(szbuf),&nread,NULL);		//写回管道中

		//写完后要断开链接
		DisconnectNamedPipe(curpipe.hpipe);
	}

	return 0;
}

//开启服务,这些线程是一产次性开完?还是等到客户端有链接才会开?
void start()
{
	for (int i = 0; i < startthreadnum; i++)
	{
		//创建管道
		pipeist[i].hpipe = CreateNamedPipeA(
			pipename,//管道名称
			PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,		//管道读写属性
			PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,		//消息模式,读模式,等待模式阻塞
			startthreadnum,		//先开10
			0,		//输出缓冲区大小,为 0 实时生效
			0,		//输入缓冲区大小 为 0 实时生效
			3000,			//超时,3秒等待
			NULL);		//安全
		pipeist[i].id = i;
		if (pipeist[i].hpipe == INVALID_HANDLE_VALUE)
		{
			printf("%d 创建失败!\n",i);
			return;
		}

		printf("%d 线程运行......\n", i);

		//创建事件  处理完了就释放等待下个 线程
		pipeist[i].hevent = CreateEventA(NULL, FALSE, FALSE, FALSE);	

		//创建线程
		pipeist[i].hthread = CreateThread(NULL, 0, severThread, &pipeist[i], 0, NULL);
				
	}

	printf("sever start...\n");
}

//结束服务
void end()
{

}

void main()
{
	start();

	system("pause");
}


下面提供一个压力测试的代码:

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

void main()
{
	//system() 不行,不能异步。
	while (1)
	{
		for (int i = 0; i < 100; i++)
		{
			
			//system("I:\\fudan\\C\\Library\\黑马\\CGI\\管道SERVER\\Debug\\客户端.exe");
			//ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件、打开一个目录、打印一个文件等等
			ShellExecuteA(NULL,
				"open",	//指定动作, 譬如: open、runas、print、edit、explore、find
				"I:\\fudan\\C\\Library\\黑马\\CGI\\管道SERVER\\Debug\\客户端.exe",	//指定要打开的文件或程序
				NULL,	//给要打开的程序指定参数; 如果打开的是文件这里应该是 nil
				NULL,
				1	//打开选项,即是隐藏、最小化、最大化还是用最近的大小和位置显示, 激活  
				);
		}
		Sleep(5000);
		
	}	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值