当前位置: 首页 > article >正文

Linux_c 有名管道练习

题目:

        使用有名管道实现两个进程间的双向通讯


程序设计:

1、程序以 ./a.out A B 和./a.out B A 的方式运行,且只编写一份源码;

2、当./a.out A B 启动程序:(以./a.out B A则反过来)

        1)生成一个A_B.fifo的管道文件(A->B),创建一个B_A.fifo的管道文件(A<-B);

        2)创建线程send_task,打开A_B.fifo,实现向B发送消息;

        3)创建线程recv_task,打开B_A.fifo文件,实现接收来自B的消息

3、当某一方放松quit时,双方退出程序并销毁相关的资源


实现代码(多线程版本):

//sT-发送线程,rT-接收线程
pthread_t sT,rT;

//判断程序入参的正确性
int checkArgs(int argc, const char*argv[]);//OK-返回0,失败-返回-1

//创建管道文件,若不存在,则新建;若存在,直接返回
void createFifo(char *filename, const char *from,const char *to);

//发送数据线程执行函数
void* sendTask(void* argv);

//接收数据线程执行函数
void* recvTask(void* argv);

int main(int argc, const char *argv[])
{
	//判断入参的合法性
	if(checkArgs(argc, argv) != 0){
		return -1;
	}

	//创建两个管道文件
	char sendFile[20];
	createFifo(sendFile, argv[1], argv[2]);
	//printf("sendFile=[%s]\n", sendFile);
	char recvFile[20];
	createFifo(recvFile, argv[2], argv[1]);
	//printf("recvFile=[%s]\n", recvFile);

	//开启发送和接受线程
	pthread_t sT,rT;
	pthread_create(&sT, NULL, sendTask, sendFile);
	pthread_create(&rT, NULL, recvTask, recvFile);
	//
	//销毁资源
	pthread_join(sT, NULL);
	pthread_join(rT, NULL);
	printf("程序已经关闭\n");

	return 0;
}


int checkArgs(int argc, const char*argv[]){
	if(argc!=3){
		printf("参数输入错误:必须以./a.out A B或./a.out B A的方式运行\n");
		return -1;
	}
	if(strcmp(argv[1],"A")==0&&strcmp(argv[2],"B")==0)
		return 0;
	if(strcmp(argv[1],"B")==0&&strcmp(argv[2],"A")==0)
		return 0;
	printf("参数输入错误:必须以./a.out A B或./a.out B A的方式运行\n");
	return -1;
}

void createFifo(char *filename, const char *from, const char *to){
	sprintf(filename,"%s_%s.fifo", from, to);
	if(mkfifo(filename, 0644)==0){
		//printf("管道文件[%s]创建成功\n", filename);
		return;
	}
	//否则,mkfifo返回错误码
	if(errno == EEXIST){//文件已经存在,这个错误直接无视掉
		//printf("管道文件[%s]已经存在,无须创建\n", filename);
		return;
	}
	perror("文件创建失败,程序即将退出");
	exit(EXIT_FAILURE);
}

void* sendTask(void* argv){
	//printf("In sendTask: %s\n", (char*)argv);

	//以写的方式打开管道文件
	int fd=open((char*)argv,O_WRONLY);
	if(fd == -1){
		perror("sendTask 文件打开失败");
		return NULL;
	}
	//
	char buf[1024];
	while(1){
		memset(buf,0,sizeof(buf));
		//从命令行终端获取用户输入的字符串
		//printf("请输入>>:");
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1]=0;//不要\n
		//将字符串发送到指定管到中
		ssize_t cnt=write(fd,buf,strlen(buf));
		if(cnt == -1){
			perror("写管道异常");
			break;
		}
		//如果发送quit指令
		if(strcmp("quit",buf)==0){
			break;
		}
	}
	//关闭自己
	close(fd);
	pthread_exit(NULL);
}

void* recvTask(void* argv){
	//printf("In recvTask: %s\n", (char*)argv);

	//以读的方式打开管道文件
	int fd=open((char*)argv, O_RDONLY);
	if(fd == -1){
		perror("recvTask:文件打开失败");
		return NULL;
	}

	char buf[1024];
	while(1){
		//接收来自管道的消息
		memset(buf,0,sizeof(buf));
		ssize_t cnt=read(fd,buf,sizeof(buf));
		if(cnt == -1){
			perror("管道读异常");
			break;
		}
		printf("收到消息:%s\n", buf);

		//如果收到quit指令
		if(strcmp("quit", buf)==0){
			//cancel发送线程线程
			//pthread_cancel(sT);
			//exit(EXIT_SUCCESS);
			//
			break;
		}
	}
	//关闭自己
	close(fd);
	pthread_exit(NULL);
}

运行效果:

遗留问题:

两个终端要分别发送quit,双方程序才能完全终止。原因大致为,程序有两个线程,一个负责发,一个负责收,发数据的线程,需要通过fgets从终端获取数据,因此在客户没有输入内容的时候,会阻塞住。且一个线程退出后,没有办法让另一个线程也停止。暂时还没有什么更好的办法。


http://www.kler.cn/news/357201.html

相关文章:

  • Facebook Marketplace为什么无法使用的原因?
  • 树莓派刷入OpenWrt后扩容overlay的方法
  • 诺贝尔物理学奖与机器学习、神经网络:一场跨时代的融合与展望
  • Spring容器详解:BeanFactory和ApplicationContext的不同
  • spring mvc后端实现过程
  • 【计算机网络 - 基础问题】每日 3 题(四十一)
  • 字节回应实习生破坏大模型训练:确有此事 但部分报道夸大失实
  • 推荐系统 # 二、推荐系统召回:协同过滤 ItemCF/UserCF、离散特征处理、双塔模型、自监督学习、多路召回、曝光过滤
  • VUE 仿神州租车-开放平台
  • Java中的一些名词概念
  • C++服务端的配置文件库介绍
  • Linux 中文件的权限说明
  • 论线段树的调试
  • 如何保护您的服务器免受Shellshock Bash漏洞的影响
  • IDEA项目提交至SVNGIT仓库
  • 【升华】人工智能python重要库scikit-learn学习
  • 【ARM】MDK-Flex服务管理软件使用说明
  • 基于SpringBoot+Vue+uniapp微信小程序的校园反诈骗微信小程序的详细设计和实现(源码+lw+部署文档+讲解等)
  • 【华为HCIP实战课程十三】OSPF网络中3类LSA及区域间负载均衡,网络工程师
  • 读人工智能全传16读后总结与感想兼导读