commit f24da015d79edf4b8d5a1cec5aec37103d4b6626
Author: weijiaqiang
Date: Sat Feb 22 16:43:48 2014 +0800
测试:如果使用 O_ASYNC 和 信号处理机制。
测试结果:
如果管道描述符的状态发生改变时(可以在fd[0]上读取到数据或可以往fd[1]上写入数据)
进程会收到信号。
commit b7de551beea93ddf05da4da7281349ecfcf18c9c
Author: weijiaqiang
Date: Sat Feb 22 16:26:26 2014 +0800
测试: 当管道的读端处于非阻塞状态下,read 一个没有数据的管道时
会有什么影响?
测试结果:
read 函数返回 -1, errno 别设置为 EAGIN
commit bed40410ba3c14fbaec1d6f14e64e990c9bf2ef7
Author: weijiaqiang
Date: Sat Feb 22 16:06:52 2014 +0800
测试:在Linux 下,宏定义 PIPE_BUF 的值
测试结果:
PIPE_BUF 宏定义在 /usr/include/linux/limits.h 头文件中定义
它的值为4096, 这个值的含义为当多个往同一个管道写时,写入的
数据小于PIPE_BUF 所定义的字节数,系统可以保证这次该写操作是
原子的。
commit e637dd4f551b14badca5110a47590280f4b87a6f
Author: weijiaqiang
Date: Sat Feb 22 16:01:31 2014 +0800
测试: 当管道所有的写端都已经关闭时, 调用read
从管道的读端读数据会有什么应影响?
测试结果:
当read读出管道内所有数据之后,会返回0(end of
file)的意思,读端可以通过这个返回值看看,管道是否还有写端
commit 27814d9c694b7cd630ceecd04b5c7df0b5367c85
Author: weijiaqiang
Date: Sat Feb 22 15:53:36 2014 +0800
测试管道的读端关闭后,往管道上写数据会有如何影响。
测试的结果是:
进程会收到SIGPIPE信号,同时 errno 被设置为 EPIPE
commit ecc0da3180274217e45fb83f3738c5160b6c03f5
Author: weijiaqiang
Date: Sat Feb 22 15:45:37 2014 +0800
测试管道的默认缓冲区大小, 测试结果为65535个字节
commit f390ae0d9c2b90a9f6eecbe9e4da0efe568c0a68
Author: weijiaqiang
Date: Sat Feb 22 15:41:50 2014 +0800
创建 读写会阻塞的 管道
点击(此处)折叠或打开
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void sig_pipe(int signo, siginfo_t* info, void* context)
{
cout << "[INFO] ############## in sigal SIGPIPE handler .!" << endl;
}
int main(int argc, char* argv[])
{
/*==================== 注册信号处理函数 ========================*/
struct sigaction act;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = sig_pipe;
sigemptyset(&act.sa_mask);
if (sigaction(SIGIO, &act, NULL) == -1)
{
cerr << "[ERROR] ############# failed to call sigaction to get orginal SIGIN disption info .!" << endl;
exit(EXIT_FAILURE);
}
/* =================== 创建管道,并将管道读端的设置为读非阻塞、管道数据后信号通知 ================== */
int fd[2];
if (pipe(fd) != 0)
{
cerr << "[ERROR] ########### faile to create pipe, error message .!" << endl;
exit(EXIT_FAILURE);
}
/*======================= 将管道的读端设置为读非阻塞 ===================== */
long cur_flag = fcntl(fd[0], F_GETFL);
if (cur_flag == -1)
{
cerr << "[ERROR] ######### failed to call fcntl .!" << endl;
exit(EXIT_FAILURE);
}
cur_flag |= (O_NONBLOCK | O_ASYNC);
if (fcntl(fd[0], F_SETFL, cur_flag) == -1)
{
cerr << "[ERROR] ######### failed to call fcntl to F_SETFL, error message: " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
/* ====================== 管道有数据可读,进程接收到SIGIO 信号 ========== */
if (fcntl(fd[0], F_SETSIG, SIGIO) == -1)
{
cerr << "[ERROR] ######### failed to call fcntl to F_SETSIG, error message: " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
if (fcntl(fd[0], F_SETOWN, getpid()) == -1)
{
cerr << "[ERROR] ######### failed to call fcntl to F_SETOWN, error message: " << strerror(errno) << endl;
exit(EXIT_FAILURE);
}
/*
* 第1次测试往管道上写东西, 将会看到
* write 函数返回之前 sig_io 信号处理函数会被调用
*/
char c = 'a';
if (write(fd[1], &c, sizeof(c)) != sizeof(c))
{
cerr << "[ERROR] ########### write to pipe failed ,error message :" << strerror(errno) << endl;
}
cout << "[INFO] ########## write to pipe ok .!" << endl;
/*
* 测试从管道读消息,我们将会看到:
* 虽然管道上现在只有一个字节的数据,因为管道的读端描述符已经设置为读非阻塞,
* 所以,循环第1次调用read 能从管道上读取一个字节,第2此调用read 会返回-1,表示出错,而错误信息为 资源不可用
*/
char buf[128];
ssize_t byte_read;
while ((byte_read = read(fd[0], buf, sizeof(buf))) > 0);
cout << "The last call to read return " << byte_read << ", error message: " << strerror(errno) << endl;
cout << "================================================================" << endl;
/*
* 第2次测试往管道上写东西, 将会看到
* write 函数返回之前 sig_io 信号处理函数会被调用
*/
write(fd[1], &c, 1);
cout << "[INFO] ########## write to pipe ok .!" << endl;
// 这里没有必要显示调用close来关闭描述符,因为在main函数返回值,进程退出函数会自动
// 关闭所有打开着的文件描述符
return 0;
}
管道测试:
读端 调用open(file_name, O_RDONY | O_NONBLOCK) 来获取管道描述。 因为指定 O_NONBLOCK, 所以即使没有任何进程打开该管道写, open 都不会堵塞。
接下来,调用 read 尝试从管道读取数据,会由一下的情景。
1)当前还没有任何进程打开该管道用于写, read 的返回值是 0
2)当前有进程在打开该管道用于写, <1>管道上由数据可读,read 返回读取的数据大小;<2> 管道上没有数据, read 返回-1,errno 的值为 EAGAIN。