學習fifo管道,對read的一點總結
按照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.