0x00
管道经常用于进程间通信,进程间通过管道的读端和写端进程通信。
我们介绍一个比较简单的例子。
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1)
ERR_EXIT("pipe error");
pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid == 0) //子进程
{
sleep(5);
close(pipefd[0]); //关闭读端
write(pipefd[1], "hello", 5); //写端
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]); //父进程,关闭写端
char buf[10] = {0};
read(pipefd[0], buf, 10); //读端
printf("buf=%s\n", buf);
return 0;
}
我们来看一张图来理解这个程序。
父进程和子进程间拥有各自的文件描述符,但是他们共同操作着同一个管道,所以可以实现进程间通信。
在终端控制台的运行结果:
(等待5秒后输出)
注意read函数,是阻塞读取管道中的内容。
0x01
如果想不阻塞读取管道的内容,可以使用fcntl来改变文件属性,使文件描述符处于阻塞模式:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1)
ERR_EXIT("pipe error");
pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid == 0)
{
sleep(3);
close(pipefd[0]);
write(pipefd[1], "hello", 5);
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]);
char buf[10] = {0};
int flags = fcntl(pipefd[0], F_GETFL);
fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK);
int ret = read(pipefd[0], buf, 10);
if (ret == -1)
ERR_EXIT("read error");
printf("buf=%s\n", buf);
return 0;
}
控制台将输出:
当没有数据可读时:
O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
0x02
下午谈一下文件。列举出文件的基本操作:
1、int open(const char *pathname, int flags); 打开文件,返回文件描述符。
2、ssize_t read(int fd, void *buf, size_t count); 从文件的当前偏移读取count个字节到buf缓冲区。
3、ssize_t write(int fd, const void *buf, size_t count); 向文件的当前偏移写入count个字节,这些字节来源于buf。
4、off_t lseek(int fd, off_t offset, int whence); 用来移动文件流的读写位置。
参数 whence 为下列其中一种:
SEEK_SET 从距文件开头offset 位移量为新的读写位置。
SEEK_CUR 以目前的读写位置往后增加offset 个位移量。
SEEK_END 将读写位置指向文件尾后再增加offset 个位移量. 当whence 值为SEEK_CUR 或 SEEK_END 时, 参数offset 允许负值的出现。
5、int fcntl(int fd, int cmd, ... /* arg */ ); 用来改变文件的属性。
int flags = fcntl(pipefd[0], F_GETFL);
fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK);
6、int stat(const char * file_name, struct stat *buf); 用来获取文件状态 。
#include <sys/stat.h>
#include <unistd.h>
main()
{
struct stat buf;
stat("/etc/passwd", &buf);
printf("/etc/passwd file size = %d \n", buf.st_size);
}
参考
http://c.biancheng.net/cpp/html/326.html。