管道、共享内存、消息队列实战

无名管道:

   int pipe(int fd[2]);

   返回值:如果系统调用成功,返回0。如果系统调用失败返回- 1:
   errno =  ENFILE (没有空闲的文件描述符)
                EMFILE (系统文件表已满)
                EFAULT (fd数组无效)

#include"lib.h"     //封装的头文件

int main()
{
	int fd[2]={0}
	char buf[100]={0};
	if(pipe(fd)==-1)
	{
		perror("pipe");
		return -1;
	}
	if(fork()>0)
	{
		while(1)
		{
		   scanf("%s",buf);
		   write(fd[1],buf,strlen(buf));
		}
	}
	else
	{
		//子进程读
		while(1)
		{
		  memset(buf,0,sizeof(buf));
                  //如果写端不存在,则认为读到数据的末尾,读出的字节为0
		  if(read(fd[0],buf,sizeof(buf))==0)
		  {
			  return 0;
		  }
		  printf("read=%s\n",buf);
		}
	}
	close(fd[0]);
	close(fd[1]);
}

命名管道: 

        int mkfifo(const char *pathname, mode_t mode) ;//命名管道的创建
        返回:若成功则为0,若出错则为 -1

 demo:

#include"lib.h"
#include<errno.h>
#define FIFO_HANDLE_NEMA "/tmp/fifo_handle"
#define FIFO_CLIENT_NAME "/tmp/fifo_client_%d"

struct ps_fifo_struct{
	pid_t pid;
	char str[64];
};
int main()
{
	int fifo_handle,fifo_client;
	struct ps_fifo_struct ps_fifo;
	char client_fifo_name[64];
	int read_len;
	char answer_str[64];
	//创建有名管道
	if((mkfifo(FIFO_HANDLE_NEMA,0666)==-1) && (errno != 17))
	{
		perror("mkfifo");
		return -1;
	}
	//打开管道
	fifo_handle=open(FIFO_HANDLE_NEMA,O_RDONLY);
	if(fifo_handle==-1)
	{
		perror("name_fife open");
		return -1;
	}
	do{
		read_len=read(fifo_handle,&ps_fifo,sizeof(ps_fifo));
	
		if(read_len>0)
		{
			//读
			printf("hai,%d ,I am %d I have received the string:%s\n",ps_fifo.pid,getpid(),ps_fifo.str);
			memset(client_fifo_name,0,64);
			
			sprintf(client_fifo_name,FIFO_CLIENT_NAME,ps_fifo.pid);
			fifo_client=open(client_fifo_name,O_WRONLY);
			ps_fifo.pid=getpid();
			if(fifo_client!=-1)
			{
				//写
				write(fifo_client,&ps_fifo,sizeof(ps_fifo));
			    close(fifo_client);
			}
			
		}
		
	}while(read_len>0);
	
	close(fifo_handle);
	unlink(FIFO_HANDLE_NEMA);
	
	return 0;
}
#include"lib.h"

#define FIFO_HANDLE_NEMA "/tmp/fifo_handle"
#define FIFO_CLIENT_NAME "/tmp/fifo_client_%d"

struct ps_fifo_struct{
	pid_t pid;
	char str[64];
};
int main()
{
	int fifo_handle,fifo_client;
	struct ps_fifo_struct ps_fifo;
	char client_fifo_name[64];
	
	//打开管道 写
	fifo_handle=open(FIFO_HANDLE_NEMA,O_WRONLY);
	if(fifo_handle==-1)
	{
		perror("name_fife open");
		return -1;
	}
	ps_fifo.pid=getpid();
	memset(client_fifo_name,0,sizeof(client_fifo_name));
	sprintf(client_fifo_name,FIFO_CLIENT_NAME,ps_fifo.pid);

	if(access(client_fifo_name,F_OK)==-1)
    {			
          if(mkfifo(client_fifo_name,0666)!=0)
		  {
			  fprintf(stderr,"Could Not Create FIFO %s\n",client_fifo_name);
			  return -1;
		  }
			
	}
	sprintf(ps_fifo.str,"hello I am %d",ps_fifo.pid);
	//printf("%d sent:%s \n",ps_fifo.pid,ps_fifo.str);
	write(fifo_handle,&ps_fifo,sizeof(ps_fifo));
	fifo_client=open(client_fifo_name,O_RDONLY);
	if(fifo_client!=-1)
	{
		if(read(fifo_client,&ps_fifo,sizeof(ps_fifo))>0)
		{
			printf("received from %d : %s\n",ps_fifo.pid,ps_fifo.str);
		    close(fifo_client);
		}
	   
	}	
	close(fifo_handle);
	unlink(client_fifo_name);
	
	return 0;
}

  运行截图:

  

  

消息队列:

          消息队列的实现包括创建和打开队列、添加消息、读取消息这几种操作。    

          struct msgbuf
         {
           long mtype; /* type of message */

           char mtext[1]; /* message text */
         };

          int msgget (key_t key, int flag)                 
          参数flag可以为以下:
          IPC_CREAT、IPC_EXCL、0666

          返回:成功返回消息队列描述字,否则返回-1。      

          int msgsnd (int msgid, struct msgbuf *msgp, size_t msgsz, int flag) //把消息添加到消息队列中(也就是发送消息)

          返回:成功返回0,否则返回-1。

          *msgp  指向要发送消息的指针,消息一般是一个带有long类型的消息类型结构体
           msgsz 发送消息的长度,不包括消息类型
           flag     控制在消息队列已满时的选项
                      IPC_NOWAIT  立即返回错误-1  (非阻塞)
                      0  等待消息队列有可用空间       (阻塞)      

          int msgrcv (int msgid, struct        msgbuf *msgp, size_t msgsz,long   msgtyp, int flag) //读取信息
          返回:成功返回读出消息的实际字节数,否则返回-1       

         参数三:

        msgtyp是期望接收的消息类型;0:队列中第一个可用消息;>0:相同消息类型的第一个消息;<0:类型等于或小于msgtyp绝对值的消息。 mtype必须是大于0的数。

         参数四:
         flag在消息队列没有没有相应类型的消息可以接受时:IPC_NOWAIT指明立即返回,返回值为-1;若IPC_NOWAIT标志被清除,则发送进程挂起以等待第一条相同类型的消息到达。      

         int msgctl(int msgid, int cmd, struct msqid_ds *buf);

        msgid:消息队列标识符。
          cmd:采取的动作。
                 IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msgid结构中;
                 IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msgid结构中;
                 IPC_RMID:删除msgid标识的消息队列;

demo:

#include"lib.h"

struct msgbuf
{
	long mtype;      //消息类型
	char mtext[1024];
};
int main()
{
	struct msgbuf mbuf;
	mbuf.mtype=1;
	strcpy(mbuf.mtext,"hello");
	//创建和打开信息
	int msgid=msgget(1,IPC_CREAT|0666);
	if(msgid==-1)
	{
		perror("msgget");
		return -1;
	}
	msgsnd(msgid,&mbuf,sizeof(mbuf.mtext),0);

	
	return 0;
}
#include"lib.h"

struct msgbuf
{
	long mtype;      //消息类型
	char mtext[1024];
};
int main()
{
	struct msgbuf mbuf;
	//创建和打开信息
	int msgid=msgget(1,IPC_CREAT|0666);
	if(msgid==-1)
	{
		perror("msgget");
		return -1;
	}
        参数四要和来的消息类型一样,否则收不到消息
	msgrcv(msgid,&mbuf,sizeof(mbuf.mtext),1,0);

	printf("recv=%s\n",mbuf.mtext);
	
	//msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

   共享内存:          

              步骤:

              一、创建共享内存,使用shmget函数。
              二、映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数。           

              int shmget ( key_t key, int size, int shmflg );
              用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。

             参数二:内存空间大小

             参数三:IPC_CREAT   IPC_EXCL  0666                          
             返回值:如果成功,返回共享内存段标识符。
                           如果失败,则返回- 1:             

             void *shmat ( int shmid, char *shmaddr, int shmflg);

             返回值:如果成功,则返回共享内存段连接到进程中的地址,失败则返回(void *)- 1.   

            当一个进程不在需要共享的内存段时,它将会把内存段从其地址空间中脱离。
            int shmdt ( void *shmaddr );

            返回值:成功返回0,失败返回- 1:     

            int shmctl(int shm_id,int cmd,struct shmid_ds *buf);

             cmd:
                IPC_STAT:该命令用来获取共享内存信息,返回的信息存贮在buf指向的结构中;
                IPC_SET:该命令用来设置共享内存的属性,要设置的属性存储在buf指向的msqid结构中;
                IPC_RMID:删除shm_id标识的共享内存

#include "lib.h"

int main()
{
	key_t key=ftok("/home/ubuntu",1);
	int shmid=shmget(key,1024,IPC_CREAT|0666);
	pid_t pid=fork();
	
	if(pid==0)
	{
		int semid=semget(key,1,IPC_CREAT|0666);
		struct sembuf msem;
	        msem.sem_num=0;
		msem.sem_op=-1;
		msem.sem_flg=SEM_UNDO;
		int *p=shmat(shmid,NULL,0);  
		while(1)
		{
			semop(semid,&msem,1);
			printf("%d\n",*p);
			sleep(1);
		}
	}
    else
	{
		int semid=semget(key,1,IPC_CREAT|0666);
		struct sembuf msem;
	        msem.sem_num=0;
		msem.sem_op=1;
		msem.sem_flg=SEM_UNDO;
                int *num=shmat(shmid,NULL,0);
		while(1)
		{
		  scanf("%d",num);
		  semop(semid,&msem,1);
		}	
	}
	
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值