【问题标题】:c - How to check EOF when read() on FIFOc - 如何在 FIFO 上的 read() 时检查 EOF
【发布时间】:2016-03-23 11:23:20
【问题描述】:

在客户端-服务器程序中,需要在FIFO 上检查read()EOF

问题:

  • FIFO 中的 EOF 是否返回 0-1 并设置了 errno?
  • 该规则是否也适用于其他 IPC 设施?

@Update

我仍然发现结果有用,所以需要继续询问。


源代码如下:

cs_fifo.h:

// fifo header
#ifndef _CS_FIFO
#define _CS_FIFO

#define CLIENT_DATA_SIZE 2
#define SERVER_DATA_SIZE 10

#define SERVER_FIFO_PATH "/tmp/server_fifo"

#define CLIENT_COUNT 3

#endif

fifo_server.c:

// client - server fifo, server part,
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "cs_fifo.h"

int fifo_server() {
    int flag;
    int fd;

    char buf[CLIENT_DATA_SIZE];

    // remove fifo, before create
    remove(SERVER_FIFO_PATH);

    // create fifo
    mode_t mode = 0644;
    if((flag = mkfifo(SERVER_FIFO_PATH, mode)) == -1) {
        printf("error while mkfifo(): %s\n", strerror(errno));
        return -1;
    }
    printf("server fifo created, path: %s\n", SERVER_FIFO_PATH);

    // open for read
    if((fd = open(SERVER_FIFO_PATH, O_RDONLY)) == -1) {
        printf("error while open(): %s\n", strerror(errno));
        exit(-1);
    }

    // loop to receive data from client,
    while(1) {
        // read from fifo
        if((flag = read(fd, buf, CLIENT_DATA_SIZE)) == -1) {
            printf("error while read(): %s\n", strerror(errno));
            exit(0);
        } else if(flag == 0) { // no data
            printf("no data\n");
            sleep(1);
            continue;
        }
        // data received,
        printf("receive data: %s\n", buf);

        // send data back to client's fifo,
        // TODO
    }

    // remove fifo, after finish using,
    remove(SERVER_FIFO_PATH);

    return 0;
}

int main(int argc, char * argv[]) {
    return fifo_server();
}

fifo_client.c:

// client - server fifo, client pool part,
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "cs_fifo.h"

int fifo_client_pool() {
    int flag;
    int server_fd;

    char data[CLIENT_DATA_SIZE];

    int i = 0;
    pid_t cpid;
    char identity;

    // open for write
    if((server_fd= open(SERVER_FIFO_PATH, O_WRONLY)) == -1) {
        printf("error while open(): %s\n", strerror(errno));
        exit(-1);
    }

    // create child processes as clients,
    while(i < CLIENT_COUNT) {
        switch(cpid=fork()) {
            case -1: // failed
                printf("error while fork(): %s\n", strerror(errno));
                exit(errno);
            case 0: // success, child process goes here
                printf("child process created, pid [%d], parent pid [%d]\n",(int)getpid(), (int)getppid());
                identity = i + 65; // start from 'A'

                // prepare data
                data[0] = identity;
                data[1] = '\0';

                // write to fifo
                if((flag = write(server_fd, data, CLIENT_DATA_SIZE)) == -1) {
                    printf("[%c] error while write(): %s\n", identity, strerror(errno));
                    _exit(-1);
                }
                printf("[%c] send data to server\n", identity);

                _exit(0);

                break;
            default: // success, parent process goes here
                // sleep a while,
                sleep(1);
                break;
        }

        i++;
    }

    if((flag = close(server_fd)) != 0) {
        printf("error while close(): %s\n", strerror(errno));
    }

    return 0;
}

int main(int argc, char * argv[]) {
    return fifo_client_pool();
}

编译:

服务器:gcc -Wall fifo_server.c -o server

客户:gcc -Wall fifo_client_pool.c -o client_pool

执行:

第一个启动服务器:./server

然后启动客户端池:./client_pool

结果:

  • 服务器启动,客户端启动前阻塞。

  • 然后客户端启动,服务器从3个客户端分别收到1个请求,一共3个。

  • 然后所有客户端进程终止,然后服务器的 read() 继续返回 0 而没有阻塞。


未来的问题是:

  • 所有客户端终止后,服务器的read()不应该阻塞吗?因为它处于阻塞模式?

【问题讨论】:

    标签: c linux ipc eof fifo


    【解决方案1】:

    全部read返回零的描述符中读取,表示“关闭”或“结束”。

    如果你有一个阻塞描述符(默认),那么read 将在当前没有可读取的内容时阻塞。如果描述符是非阻塞的,则 read 返回 -1 并将 errno 设置为 EAGAINEWOULDBLOCK 如果没有可读取的内容。

    【讨论】:

    • 在我的程序中,read()0 返回,它处于阻塞模式,读取器仍然打开,但所有写入器都关闭,这是正常的还是使用的?
    • @EricWang 当管道 (FIFO) 从另一端关闭时,当没有更多内容可读取时,read 将返回零,您应该关闭您的一端。对于阻塞描述符,read 只会阻塞(不返回),直到有东西要读取。
    • @EricWang 如果read 返回零,则表示您已完成接收,您将不会再收到任何东西。所以你应该关闭描述符并退出你所在的循环,不要继续希望会有更多,因为它不会。当read 返回零时,这并不意味着“没有数据”,而是意味着“文件结束”或“连接关闭”或“管道中没有更多数据”,这不是暂时缺少数据,而是永久结束数据流。
    • 是的。如果管道的另一端关闭,则管道已关闭,不再有数据。所以 read() 解除阻塞,并返回 0,这样你就可以对这个事实采取行动了。
    • 是的 - 我不会特别推荐为多个客户端使用命名的 fifo。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多