按照unix网络编程第二版中的fifo管道例子,跑了一下,发现如下问题:
当server通过fifo管道把文件内容发传完给client后,client也正确接收完,server就退出,但client没退出,还在死循环????
原因:client中的read调用是阻塞的,不会主动退了, 所以一直在监测管道的数据到来(不像socket那样,一端关闭,另一端就会返回),其实它的确不知是否结束。
解决方法:要对方结束,就要在应用上处理,通过指定的协议,让对方知道传输己结束,修改后的client和server如下:
void client(int readfd, int writefd)
{
size_t len;
size_t n;
char buf[100];
fgets(buf, 100, stdin);
len = strlen(buf);
if ('\n' == buf[len -1])
{
len--;
}
write(writefd, buf, len);
while( (n = read(readfd, buf, 100)) > 0 )
{
write(STDOUT_FILENO, buf, n);
if ( strcmp(buf, "over") == 0 )
{
break;
}
}
std::cout << "client while over" << std::endl;
}
void server(int readfd, int writefd)
{
int fd;
size_t n;
char buf[100];
if ((n = read(readfd, buf, 100)) == 0)
{
std::cout << "end-of-file while reading pathname" << std::endl;
}
buf[n] = '\0';
if ((fd = open(buf, O_RDONLY)) < 0)
{
snprintf(buf + n, sizeof(buf) - n, ": can't open, %s\n", strerror(errno));
n = strlen(buf);
write(writefd, buf, n);
}
else
{
while ( (n = read(fd, buf, 100)) > 0 )
{
write(writefd, buf, n);
}
write(writefd, "over", 5);
std::cout << "server while over" << std::endl;
close(fd);
}
}
================================================================================================================
往后的例子看到,更好的办法是:
子进程把writefd关闭,这样父过程client中的read调用就会返回。
注UNPv2中4.10节:
在使用管道或FIFO时,可以通过关闭IPC通道来通知对方己到达输入文件的结尾。不过我们通过发送回一个长度为0的消息来达到同样的目的,因为存在没有文件结束符概念的其他类型的IPC.