读写FIFO文件 - Linux

9

我一直在努力理解先进先出(FIFO),并编写了一个简单的服务器和客户端程序。


我不想做什么高深的事情,只是要有一个进程充当“服务器”的角色,该进程将“监听”另一个进程(客户端)发送的任何消息。


这是我的代码:

server.c

#include<stdio.h>
#include <fcntl.h>
#include <stdlib.h>


#define INGOING "clientToServer.fifo"

#define BUFFER 200

int main(int argc, char *argv[]) {

    char in[BUFFER];

    mkfifo(INGOING, 0666);

    printf("Welcome to server.\n");
    printf("channel for sending messages to server is %s\n", INGOING);

    int in_fd=open(INGOING, O_RDONLY);

    if (in_fd==-1) {
        perror("open error");
        exit(-1);
    }

    while (read(in_fd, in, BUFFER)>0) {
        printf("You sent %s to server.\n", in);
    }

    return 2;
}

如您所见,这很简单。当我在后台运行时使用./server.out&,它将在read调用处被阻塞并等待任何人向clientToServer.fifo写入内容。到目前为止都很好。

现在,请考虑客户端:

client.c
#include<stdio.h>
#include<fcntl.h>
#include<string.h>


#define BUFFER 200

int main(int argc, char *argv[]) {

    char input[BUFFER]={0};
    int out_fd=open("clientToServer.fifo", O_WRONLY);

    if (out_fd==-1) {
        perror("open error");
    }

    while (1) {

        printf("What would you like to send to server? (send Quit to quit)\n");
        fgets(input, BUFFER, stdin);
        if (input[strlen(input)-1]=='\n') {
            input[strlen(input)-1]='\0';
        }

        if (strcmp(input, "Quit")==0) {
            printf("Bye!");
            break;
        }

        if (write(out_fd, input, strlen(input))==-1) {
            perror("write error");
        }
    }

    return 1;
}

这是客户端。代码也很简单。当我在shell中使用./a.out运行它时,它可以发送消息,而server.out进程会打印You sent %s to server.
问题在于,当我通过客户端向服务器发送Quit时,尽管a.out进程按预期终止,但是server.out中的while循环也会停止。这意味着read不再阻塞server.out进程并等待其他客户机,而是服务器程序和客户端一起结束。
为什么会发生这种情况?即使a.out进程结束后,read不应该仍然挂起server.out吗?

你的代码存在未定义行为:你从客户端发送字符串时没有添加终止符,而在读取时也没有添加终止符,这意味着服务器中的 printf 将打印一个未终止的字符串。 - Some programmer dude
@JoachimPileborg,所以:write(out_fd, input, strlen(input)+1) - so.very.tired
不:int nbytes; while ((nbytes = read(in_fd, in, sizeof(in))) > 0) printf("你发送了 [%.*s] 到服务器\n", nbytes, in); 方括号用于标记已发送的数据(因此是可选的)。 - Jonathan Leffler
你好!非常感谢你在问题中提到了这一点:“我使用./server.out&将其在后台运行,但它在read调用处被阻塞,并等待任何人向clientToServer.fifo写入”。这帮助我意识到了一些问题,因此我解决了我的问题。这与FIFO有关。我真的很喜欢这个网站和那些付出努力的人们!继续保持! - M.Ionut
2个回答

11
当我用"./server.out&"在后台运行时,它被阻塞在读取调用处,并等待任何人写入clientToServer.fifo。实际上,它被阻塞在"open"处。这是FIFO的工作方式。open(在阻塞模式下)将阻塞,直到另一端打开FIFO。服务器中的while循环也会中断。这意味着读取不再阻塞服务器进程并等待其他客户端,相反,服务器程序将结束。同样,这是正常行为。只有一个客户端进程连接到FIFO,因此当它关闭其端口时,EOF将被发送并且服务器将退出。如果多个客户端同时连接到FIFO,则直到最后一个客户端关闭它,您才会看到EOF。如果要让长时间运行的服务器持续为多个客户端提供服务,则最简单的方法是将服务器的FIFO设置为读/写方式。这样就始终有一个读者/写入者-服务器本身,即使最后一个客户端退出时,您也不会看到EOF。当需要关闭服务器时,请关闭服务器中的适当端口,并让自然过程发生,因为真正的客户端退出。

谢谢。我在哪里可以找到详细解释所有这些的手册?我在Linux手册中找不到它... - so.very.tired
1
我不确定有关于这些东西的手册。没有什么能够替代好的、详细的UNIX书籍和对文档页的迭代仔细阅读。网络上有大量质量参差不齐的资源材料可供使用。其中一个备受推崇的是Beej's Guides - Duck
看起来正是我需要的! :-) - so.very.tired

3
当客户端退出时,它会关闭管道连接,这会导致服务器中的read函数返回0,从而退出循环。

当我最初运行server.out时,为什么它在read处停止了进程?在运行a.out之前没有打开任何管道连接。 - so.very.tired

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接