Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 准备就绪时不会读取命名管道。(它在gdb内部工作)_C_Unix_Pipe_Named Pipes_Fifo - Fatal编程技术网

C 准备就绪时不会读取命名管道。(它在gdb内部工作)

C 准备就绪时不会读取命名管道。(它在gdb内部工作),c,unix,pipe,named-pipes,fifo,C,Unix,Pipe,Named Pipes,Fifo,2014年12月20日更新:此问题已解决,请参阅问题底部的工作代码 设计 有四个客户端处理一些数据,然后通过命名管道FIFO将其传递给服务器进程 问题 当在gdb之外运行服务器时,不进入gdb也会出现同样的问题,只读取一个管道。Select返回1,FD_ISSET仅对一个管道作出反应,并且在执行期间保持同一管道 查看/proc/[PID]/{fd,fdinfo}会发现其他管道仍处于打开状态,尚未读取。fdinfo中的pos字段为0 问题 我需要更改什么以交错方式读取所有四个管道 测验 为了模拟客

2014年12月20日更新:此问题已解决,请参阅问题底部的工作代码

设计 有四个客户端处理一些数据,然后通过命名管道FIFO将其传递给服务器进程

问题 当在gdb之外运行服务器时,不进入gdb也会出现同样的问题,只读取一个管道。Select返回1,FD_ISSET仅对一个管道作出反应,并且在执行期间保持同一管道

查看/proc/[PID]/{fd,fdinfo}会发现其他管道仍处于打开状态,尚未读取。fdinfo中的pos字段为0

问题 我需要更改什么以交错方式读取所有四个管道

测验 为了模拟客户端,我使用一个12字节的随机文件,该文件被传输到命名管道上

随机文件是通过以下方式生成的:

dd if=/dev/urandom of=test.bin bs=1024 count=$((1024*12))
然后在单独的终端中按以下顺序执行

terminal 1:
./server.out
terminal 2:
cat test.bin > d0
terminal 3:
cat test.bin > d1
terminal 4:
cat test.bin > d2
terminal 5:
cat test.bin > d3
生成文件

来源

这些客户端称为加密狗

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define NR_OF_DONGLES 4

int do_something(int fd);

int main()
{
    fd_set read_fd_set;
    FD_ZERO(&read_fd_set);

    int dongles[NR_OF_DONGLES];
    /*Create FIFO */
    for(int i = 0; i < NR_OF_DONGLES; i++)
    {
        char name[255];
        snprintf(name, sizeof(name), "d%d", i);
        if(mkfifo(name, 0666) == -1)
        {
            fprintf(stderr, "Failed to create fifo %s \t Error: %s", name, name);
            exit(EXIT_FAILURE);
        }

        int dongle = open(name, O_RDONLY);
        if(dongle > 0)
        {
            fprintf(stderr,"set dongle %s\n", name);
            FD_SET(dongle, &read_fd_set);
            dongles[i] = dongle;
        }
        else
        {
            fprintf(stderr, "failed to open: %s\nerror: %s\n", name, strerror(errno));
            exit(EXIT_FAILURE);
        }
    }

    int closed = 0;
    int isset[NR_OF_DONGLES];
    memset(isset, 0, sizeof(isset));

    while(closed < NR_OF_DONGLES)
    {
        int active;
        if((active = select (FD_SETSIZE , &read_fd_set, NULL,NULL,NULL)) < 0)
        {
            fprintf(stderr, "select failed\n errno: %s\n",strerror(errno));
            exit(EXIT_FAILURE);
        }
        fprintf(stderr, "active devices %i\n", active);

        for(int i = 0; i < NR_OF_DONGLES; ++i)
        {
            int dongle = dongles[i];
            if(FD_ISSET(dongle, &read_fd_set))
            {

                isset[i] += 1;
                int size = do_something(dongle);
                fprintf(stderr, "round %i \tdongle %i \tread %i bytes\n", isset[i],i, size);
                if(size == 0)
                {

                    if(close(dongle) == -1)
                    {
                        fprintf(stderr,"Could not close dongle %i\nError: %s\n",
                                i,strerror(errno));
                    }

                    closed += 1;
                    fprintf(stderr, "closed dongle %i \t number of closed dongles %i\n",
                            i, closed);

                    FD_CLR(dongle, &read_fd_set);
                }

            }   
        }
    }

    exit(EXIT_SUCCESS);
}

#define BLOCK_SIZE (8*1024)
/*
 * If the size is zero we reached the end of the file and it can be closed
 */
int do_something(int fd)
{
    int8_t buffer[BLOCK_SIZE];
    ssize_t size = read(fd, buffer, sizeof(buffer));
    if(size > 0)
    {
        //Process read data
    }
    else if(size == -1)
    {
        fprintf(stderr, "reading dongle failed\nerrno: %s", strerror(errno));
        return -1;
    }

    return size;
}

您可以尝试在Solaris上通过strace truss运行代码,在FreeBSD上通过ktrace/kdump运行代码。对我来说,它只在opend0上暂停。因此,服务器不会在cat创建其他管道之前创建所有管道

我的狗。。。打开后不正确:如果失败,打开返回-1,而不是0

因此,我认为您的程序无法处理您希望只正确打开一个管道的文件


还有一个问题与选择使用有关。在每次调用select之前,您应该重新初始化read_fd_set,因为在每次调用select后,只有描述符保留了标记数据,其他描述符则被清除。

经过一些修改,我得到了它。在我的MacOSX open上。。。直到FIFO上有东西出现时才会停止。考虑下面的程序;只要您开始将数据馈送到d0、d1等中,它就会工作。但在此之前,该程序的输出仅为:

Creating dongle d0
Creating dongle d1
Creating dongle d2
Creating dongle d3
Opening dongle d0
所以我打开了open的主页,你瞧,有一个非Block的旗帜。添加了这些代码后,下面的代码就像一个符咒。仅供参考,POSIX并没有说打开FIFO应该被阻止,但我发现了一些实现所做的评论

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/select.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define NR_OF_DONGLES 4
#define BLOCK_SIZE (8*1024)

// Prints error and stops program
int error(char const *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    exit(1);
}

// Alternative for printf() that flushes stdout
void msg(char const *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    fflush(stdout);
}

// Reads an open readable fd
int do_something(int fd) {
    int8_t buffer[BLOCK_SIZE];
    ssize_t size = read(fd, buffer, sizeof(buffer));
    if(size > 0)
        msg("Got data from fd %d, length %ld\n", fd, size);
    else if (size == -1)
        error("Reading dongle fd %d failed: %s\n", fd, strerror(errno));
    else
        msg("Dongle with fd %d signals EOF\n", fd);

    return size;
}

int main() {
    int dongles[NR_OF_DONGLES];

    // Create the dongles, open, add to list of open fd's
    for (int i = 0; i < NR_OF_DONGLES; i++) {
        char name[255];
        snprintf(name, sizeof(name), "d%d", i);
        msg("Creating dongle %s\n", name);
        if (mkfifo(name, 0666) == -1 && errno != EEXIST)
            error("Failed to create fifo %s: %s\n", name, strerror(errno));
    }
    for (int i = 0; i < NR_OF_DONGLES; i++) {
        char name[255];
        snprintf(name, sizeof(name), "d%d", i);
        msg("Opening dongle %s\n", name);

        /* ****************************************
         * Here it is, first test was with
         * int fd = open(name, O_RDONLY);
         * which blocked at the open() call
         *******************************************/
        int fd = open(name, O_RDONLY | O_NONBLOCK);
        if (fd < 0)
            error("Cannot open dongle %s: %s\n", name, strerror(errno));
        dongles[i] = fd;
    }

    int closed = 0;
    while (closed < NR_OF_DONGLES) {
        msg("Closed dongles so far: %d\n", closed);

        // Add dongle fd's to select set, unless the fd is already closed
        // which is indicated by fd == -1
        fd_set read_fd_set;
        FD_ZERO(&read_fd_set);
        for (int i = 0; i < NR_OF_DONGLES; i++)
            if (dongles[i] > 0)
                FD_SET(dongles[i], &read_fd_set);

        // Wait for readable fd's
        int active;
        if ( (active = select (FD_SETSIZE , &read_fd_set, 0, 0, 0)) < 0 )
            error("Select failure: %s\n", strerror(errno));
        msg("Active dongles: %d\n", active);

        for (int fd = 0; fd < FD_SETSIZE; fd++)
            if (FD_ISSET(fd, &read_fd_set)) {
                msg("Fd %d is readable\n", fd);
                int size = do_something(fd);
                if (!size) {
                    // Fd signals EOF. Close dongle, remove from array
                    // of open fd's by setting to -1
                    msg("Fd %d signals EOF\n", fd);
                    if (close(fd) < 0)
                        error("Failure to close fd %d: %s\n",
                              fd, strerror(errno));
                    for (int i = 0; i < NR_OF_DONGLES; i++)
                        if (dongles[i] == fd)
                            dongles[i] = 0;
                    // Update closed fd counter
                    closed++;
                }
            }
    }
    exit(0);
}

你有设计,有问题,有测试。。。问题在哪里?首先,好的捕获,打开的检查确实是错误的。不幸的是,问题仍然存在,它没有返回-1。第二,关于战略的好建议。我没有试着用strace调试它。遗憾的是,它没有给我任何额外的信息。对我来说,它没有挂起d0,而是暂停,因为它正在d0 cat test.bin>d0上等待编写器。读取的管道通常是d0或d1,有时是其他管道中的一个,因此读取的管道并不总是相同的。@Henk,你说得对。存在与选择相关的问题。答案已更新。这是关于FIFO打开的:如果O_NONBLOCK是清除的,则只用于读取的打开将阻止调用线程,直到线程打开文件进行写入。仅用于写入的open将阻止调用线程,直到线程打开文件进行读取。因此,它肯定会阻塞,直到FIFO被打开写入。但它不应该阻塞,直到有东西被实际写入。如果编写器只是打开,然后在一段时间内什么也不做,那么读者的打开应该会成功,然后阅读将被阻止。@WumpusQ.Wumbley-是的,我也希望看到它。希望看到它吗?unix上一直都是这样。如果你认为MacOS X不符合我写的,我怀疑你误解了什么。进程可以在非阻塞模式下打开FIFO。在这种情况下,即使写端还没有人打开,只读打开也会成功,如果ENXIO没有这样的设备或地址,则只读打开会失败,除非另一端已经打开。从:,Linux fifo7手册页。因此,在这种情况下,如果在写入之前先打开读取,则需要非阻塞模式。看起来我们在同一页上,重新阅读后,MacOSX和Linux的行为类似。
Creating dongle d0
Creating dongle d1
Creating dongle d2
Creating dongle d3
Opening dongle d0
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/select.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define NR_OF_DONGLES 4
#define BLOCK_SIZE (8*1024)

// Prints error and stops program
int error(char const *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    exit(1);
}

// Alternative for printf() that flushes stdout
void msg(char const *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    fflush(stdout);
}

// Reads an open readable fd
int do_something(int fd) {
    int8_t buffer[BLOCK_SIZE];
    ssize_t size = read(fd, buffer, sizeof(buffer));
    if(size > 0)
        msg("Got data from fd %d, length %ld\n", fd, size);
    else if (size == -1)
        error("Reading dongle fd %d failed: %s\n", fd, strerror(errno));
    else
        msg("Dongle with fd %d signals EOF\n", fd);

    return size;
}

int main() {
    int dongles[NR_OF_DONGLES];

    // Create the dongles, open, add to list of open fd's
    for (int i = 0; i < NR_OF_DONGLES; i++) {
        char name[255];
        snprintf(name, sizeof(name), "d%d", i);
        msg("Creating dongle %s\n", name);
        if (mkfifo(name, 0666) == -1 && errno != EEXIST)
            error("Failed to create fifo %s: %s\n", name, strerror(errno));
    }
    for (int i = 0; i < NR_OF_DONGLES; i++) {
        char name[255];
        snprintf(name, sizeof(name), "d%d", i);
        msg("Opening dongle %s\n", name);

        /* ****************************************
         * Here it is, first test was with
         * int fd = open(name, O_RDONLY);
         * which blocked at the open() call
         *******************************************/
        int fd = open(name, O_RDONLY | O_NONBLOCK);
        if (fd < 0)
            error("Cannot open dongle %s: %s\n", name, strerror(errno));
        dongles[i] = fd;
    }

    int closed = 0;
    while (closed < NR_OF_DONGLES) {
        msg("Closed dongles so far: %d\n", closed);

        // Add dongle fd's to select set, unless the fd is already closed
        // which is indicated by fd == -1
        fd_set read_fd_set;
        FD_ZERO(&read_fd_set);
        for (int i = 0; i < NR_OF_DONGLES; i++)
            if (dongles[i] > 0)
                FD_SET(dongles[i], &read_fd_set);

        // Wait for readable fd's
        int active;
        if ( (active = select (FD_SETSIZE , &read_fd_set, 0, 0, 0)) < 0 )
            error("Select failure: %s\n", strerror(errno));
        msg("Active dongles: %d\n", active);

        for (int fd = 0; fd < FD_SETSIZE; fd++)
            if (FD_ISSET(fd, &read_fd_set)) {
                msg("Fd %d is readable\n", fd);
                int size = do_something(fd);
                if (!size) {
                    // Fd signals EOF. Close dongle, remove from array
                    // of open fd's by setting to -1
                    msg("Fd %d signals EOF\n", fd);
                    if (close(fd) < 0)
                        error("Failure to close fd %d: %s\n",
                              fd, strerror(errno));
                    for (int i = 0; i < NR_OF_DONGLES; i++)
                        if (dongles[i] == fd)
                            dongles[i] = 0;
                    // Update closed fd counter
                    closed++;
                }
            }
    }
    exit(0);
}