⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 11.html

📁 介绍linux下文件和设备编程
💻 HTML
📖 第 1 页 / 共 5 页
字号:
FILE*pipein_fp,*pipeout_fp;<br>charreadbuf[80];<br>/*Createonewaypipelinewithcalltopopen()*/<br>if((pipein_fp=popen(&quot;ls&quot;,&quot;r&quot;))==NULL)<br>{<br>perror(&quot;popen&quot;);<br>exit(1);<br>}<br>/*Createonewaypipelinewithcalltopopen()*/<br>if((pipeout_fp=popen(&quot;sort&quot;,&quot;w&quot;))==NULL)<br>{<br>perror(&quot;popen&quot;);<br>exit(1);<br>}<br>/*Processingloop*/<br>while(fgets(readbuf,80,pipein_fp))<br>fputs(readbuf,pipeout_fp);<br>/*Closethepipes*/<br>pclose(pipein_fp);<br>pclose(pipeout_fp);<br>return(0);<br>}<br>最后,我们再看一个使用popen()的例子。此程序用于创建一个命令和文件之间的管道:<br>#include&lt;stdio.h&gt;<br>intmain(intargc,char*argv[])<br>{<br>FILE*pipe_fp,*infile;<br>charreadbuf[80];<br>if(argc!=3){<br>fprintf(stderr,&quot;USAGE:popen3[command][filename]\n&quot;);<br>exit(1);<br>}<br>/*Open up input file*/<br>if((infile=fopen(argv[2],&quot;rt&quot;))==NULL)<br>{<br>perror(&quot;fopen&quot;);<br>exit(1);<br>}<br>/*Create one way pipe line with call topopen()*/<br>if((pipe_fp=popen(argv[1],&quot;w&quot;))==NULL)<br>{<br>perror(&quot;popen&quot;);<br>exit(1);<br>}<br>/*Processingloop*/<br>do{<br>fgets(readbuf,80,infile);<br>if(feof(infile))break;<br>fputs(readbuf,pipe_fp);<br>}while(!feof(infile));<br>fclose(infile);<br>pclose(pipe_fp);<br>return(0);<br>}<br>下面是使用此程序的例子:<br>popen3sortpopen3.c<br>popen3catpopen3.c<br>popen3morepopen3.c<br>popen3catpopen3.c|grepmain<p><p><p><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I242" ID="I242"></A><center><b><font size=+2>命名管道</font></b></center><br>&nbsp;&nbsp;&nbsp; 命名管道和一般的管道基本相同,但也有一些显著的不同:<p>*命名管道是在文件系统中作为一个特殊的设备文件而存在的。<br>*不同祖先的进程之间可以通过管道共享数据。<br>*当共享管道的进程执行完所有的I/O操作以后,命名管道将继续保存在文件系统中以便以后使用。<p>&nbsp;&nbsp;&nbsp; 一个管道必须既有读取进程,也要有写入进程。如果一个进程试图写入到一个没有读取进程的管道中,那么系统内核将会产生SIGPIPE信号。当两个以上的进程同时使用管道时,这一点尤其重要。<p><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I243" ID="I243"></A><center><b><font size=+2>创建FIFO</font></b></center><br>&nbsp;&nbsp;&nbsp; 可以有几种方法创建一个命名管道。头两种方法可以使用shell。<p>mknodMYFIFOp<br>mkfifoa=rwMYFIFO<br>&nbsp;&nbsp;&nbsp; 上面的两个命名执行同样的操作,但其中有一点不同。命令mkfifo提供一个在创建之后直接改变FIFO文件存取权限的途径,而命令mknod需要调用命令chmod。<br>&nbsp;&nbsp;&nbsp; 一个物理文件系统可以通过p指示器十分容易地分辨出一个FIFO文件。<p>$ls-lMYFIFO<br>prw-r--r--1rootroot0Dec1422:15MYFIFO|<p>&nbsp;&nbsp;&nbsp; 请注意在文件名后面的管道符号“|”。<br>&nbsp;&nbsp;&nbsp; 我们可以使用系统调用mknod()来创建一个FIFO管道:<p>库函数:mknod();<br>原型:intmknod(char*pathname,mode_tmode,dev_tdev);<br>返回值:如果成功,返回0<br>如果失败,返回-1:errno=EFAULT(无效路径名)<br>EACCES(无存取权限)<br>ENAMETOOLONG(路径名太长)<br>ENOENT(无效路径名)<br>ENOTDIR(无效路径名)<p>&nbsp;&nbsp;&nbsp; 下面看一个使用C语言创建FIFO管道的例子:<p>mknod(&quot;/tmp/MYFIFO&quot;,S_IFIFO|0666,0);<p>&nbsp;&nbsp;&nbsp; 在这个例子中,文件/tmp/MYFIFO是要创建的FIFO文件。它的存取权限是0666。存取权限<br>也可以使用umask修改:<p>final_umask=requested_permissions&amp;~original_umask<p>&nbsp;&nbsp;&nbsp; 一个常用的使用系统调用umask()的方法就是临时地清除umask的值:<br>umask(0);<br>mknod(&quot;/tmp/MYFIFO&quot;,S_IFIFO|0666,0);<p>&nbsp;&nbsp;&nbsp; 另外,mknod()中的第三个参数只有在创建一个设备文件时才能用到。它包括设备文件的<br>主设备号和从设备号。<br>}<br>}<p><p><p><br><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I244" ID="I244"></A><center><b><font size=+2>操作FIFO</font></b></center><br>&nbsp;&nbsp;&nbsp; FIFO上的I/O操作和正常管道上的I/O操作基本一样,只有一个主要的不同。系统调用open用来在物理上打开一个管道。在半双工的管道中,这是不必要的。因为管道在系统内核中,而不是在一个物理的文件系统中。在我们的例子中,我们将像使用一个文件流一样使用管道,也就是使用fopen()打开管道,使用fclose()关闭它。<br>&nbsp;&nbsp;&nbsp; 请看下面的简单的服务程序进程:<br>#include&lt;stdio.h&gt;<br>#include&lt;stdlib.h&gt;<br>#include&lt;sys/stat.h&gt;<br>#include&lt;unistd.h&gt;<br>#include&lt;linux/stat.h&gt;<br>#defineFIFO_FILE&quot;MYFIFO&quot;<br>intmain(void)<br>{<br>FILE*fp;<br>charreadbuf[80];<br>/*CreatetheFIFOifitdoesnotexist*/<br>umask(0);<br>mknod(FIFO_FILE,S_IFIFO|0666,0);<br>while(1)<br>{<br>fp=fopen(FIFO_FILE,&quot;r&quot;);<br>fgets(readbuf,80,fp);<br>printf(&quot;Receivedstring:%s\n&quot;,readbuf);<br>fclose(fp);<br>return(0);<br>&nbsp;&nbsp;&nbsp; 因为FIFO管道缺省时有阻塞的函数,所以你可以在后台运行此程序:<br>$fifoserver&amp;<br>&nbsp;&nbsp;&nbsp; 再来看一下下面的简单的客户端程序:<br>#include&lt;stdio.h&gt;<br>#include&lt;stdlib.h&gt;<br>#defineFIFO_FILE&quot;MYFIFO&quot;<br>intmain(int argc,char* argv[])<br>{<br>FILE*fp;<br>if(argc!=2){<br>printf(&quot;USAGE:fifoclient[string]\n&quot;);<br>exit(1);<br>}<br>if((fp=fopen(FIFO_FILE,&quot;w&quot;))==NULL){<br>perror(&quot;fopen&quot;);<br>exit(1);<br>}<br>fputs(argv[1],fp);<br>fclose(fp);<br>return(0);<br>}<p><p><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I245" ID="I245"></A><center><b><font size=+2>阻塞FIFO</font></b></center><br>&nbsp;&nbsp;&nbsp; 一般情况下,FIFO管道上将会有阻塞的情况发生。也就是说,如果一个FIFO管道打开供读取的话,它将一直阻塞,直到其他的进程打开管道写入信息。这种过程反过来也一样。如果你不需要阻塞函数的话,你可以在系统调用open()中设置O_NONBLOCK标志,这样可以取消缺省的阻塞函数。<p><p><p><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I246" ID="I246"></A><center><b><font size=+2>消息队列</font></b></center><br>&nbsp;&nbsp;&nbsp; 在UNIX的SystemV版本,AT&amp;T引进了三种新形式的IPC功能(消息队列、信号量、以及共享内存)。但BSD版本的UNIX使用套接口作为主要的IPC形式。Linux系统同时支持这两个版本。<br><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I247" ID="I247"></A><center><b><font size=+2>msgget()</font></b></center><br>系统调用msgget()<p>&nbsp;&nbsp;&nbsp; 如果希望创建一个新的消息队列,或者希望存取一个已经存在的消息队列,你可以使用系统调用msgget()。<p>系统调用:msgget();<br>原型:intmsgget(key_t key,int msgflg);<br>返回值:如果成功,返回消息队列标识符<br>如果失败,则返回-1:errno=EACCESS(权限不允许)<br>EEXIST(队列已经存在,无法创建)<br>EIDRM(队列标志为删除)<br>ENOENT(队列不存在)<br>ENOMEM(创建队列时内存不够)<br>ENOSPC(超出最大队列限制)<p>&nbsp;&nbsp;&nbsp; 系统调用msgget()中的第一个参数是关键字值(通常是由ftok()返回的)。然后此关键字值将会和其他已经存在于系统内核中的关键字值比较。这时,打开和存取操作是和参数msgflg中的内容相关的。<br>IPC_CREAT如果内核中没有此队列,则创建它。<br>IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。<p>&nbsp;&nbsp;&nbsp; 如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。<br>下面看一个打开和创建一个消息队列的例子:<br>intopen_queue(key_t keyval)<br>{<br>intqid;<br>if((qid=msgget(keyval,IPC_CREAT|0660))==-1)<br>{<br>return(-1);<br>}<br>return(qid);<br>}<p><p><p><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I248" ID="I248"></A><center><b><font size=+2>msgsnd()</font></b></center><br>系统调用msgsnd()<p>&nbsp;&nbsp;&nbsp; 一旦我们得到了队列标识符,我们就可以在队列上执行我们希望的操作了。如果想要往队列中发送一条消息,你可以使用系统调用msgsnd():<p>系统调用:msgsnd();<br>原型:intmsgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg);<br>返回值:如果成功,0。<br>如果失败,-1:errno=EAGAIN(队列已满,并且使用了IPC_NOWAIT)<br>EACCES(没有写的权限)<br>EFAULT(msgp地址无效)<br>EIDRM(消息队列已经删除)<br>EINTR(当等待写操作时,收到一个信号)<br>EINVAL(无效的消息队列标识符,非正数的消息类型,或<br>者无效的消息长度)<br>ENOMEM(没有足够的内存复制消息缓冲区)<p>&nbsp;&nbsp;&nbsp; 系统调用msgsnd()的第一个参数是消息队列标识符,它是由系统调用msgget返回的。第二个参数是msgp,是指向消息缓冲区的指针。参数msgsz中包含的是消息的字节大小,但不包括消息类型的长度(4个字节)。<br>&nbsp;&nbsp;&nbsp; 参数msgflg可以设置为0(此时为忽略此参数),或者使用IPC_NOWAIT。<p>&nbsp;&nbsp;&nbsp; 如果消息队列已满,那么此消息则不会写入到消息队列中,控制将返回到调用进程中。如果没有指明,调用进程将会挂起,直到消息可以写入到队列中。<br>&nbsp;&nbsp;&nbsp; 下面是一个发送消息的程序:<p>intsend_message(int qid,struct mymsgbuf *qbuf)<br>{<br>intresult,length;<br>/*The length is essentially the size of the structure minus sizeof(mtype)*/<br>length=sizeof(structmymsgbuf)-sizeof(long);<br>if((result=msgsnd(qid,qbuf,length,0))==-1)<br>{<br>return(-1);<br>}<br>return(result);<br>}<p>&nbsp;&nbsp;&nbsp; 这个小程序试图将存储在缓冲区qbuf中的消息发送到消息队列qid中。下面的程序是结合了上面两个程序的一个完整程序:<p>#include&lt;stdio.h&gt;<br>#include&lt;stdlib.h&gt;<br>#include&lt;linux/ipc.h&gt;<br>#include&lt;linux/msg.h&gt;<br>main()<br>{<br>intqid;<br>key_t msgkey;<br>struct mymsgbuf{<br>longmtype;/*Message type*/<br>intrequest;/*Work request number*/<br>doublesalary;/*Employee's salary*/<br>}msg;<br>/*Generateour IPC key value*/<br>msgkey=ftok(&quot;.&quot;,'m');<br>/*Open/createthequeue*/<br>if((qid=open_queue(msgkey))==-1){<br>perror(&quot;open_queue&quot;);<br>exit(1);<br>}<br>/*Load up the message with a r bitrary test data*/<br>msg.mtype=1;/*Messagetypemustbeapositivenumber!*/<br>msg.request=1;/*Dataelement#1*/<br>msg.salary=1000.00;/*Data element #2(my yearly salary!)*/<br>/*Bombsaway!*/<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -