【问题标题】:How to send a file through a named pipe in C?如何通过C中的命名管道发送文件?
【发布时间】:2013-04-11 19:27:26
【问题描述】:

我有两个程序,服务器和客户端。服务器应该读取一个文件,然后通过命名管道将其内容发送到客户端。但是我的服务器只从文件中读取两个字符,然后退出。这段代码有什么问题?

server.c:

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

#define FIFO_NAME "american_maid"

int main(void)
{
    char line[300];
    int num, fd;
    FILE *fp;
    fp = fopen("out.txt","r");

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for readers...\n");
    fd = open(FIFO_NAME, O_WRONLY);
    printf("got a reader--type some stuff\n");

    while (fgets(line, sizeof(line), fp)) {
        if ((num = write(fd, line, strlen(line))) == -1)
            perror("write");
        else
            printf("speak: wrote %d bytes\n", num);
    }

    fclose(fp);

    return 0;
}

client.c:

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

#define FIFO_NAME "american_maid"

int main(void)
{
    char s[300];
    int num, fd;

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for writers...\n");
    fd = open(FIFO_NAME, O_RDONLY);
    printf("got a writer\n");

    do {
        if ((num = read(fd, s, 300)) == -1)
            perror("read");
        else {
            s[num] = '\0';
            printf("tick: read %d bytes: \"%s\"\n", num, s);
        }
    } while (num > 0);

    return 0;
}

【问题讨论】:

  • 如果读取 300 字节,客户端会在缓冲区 's' 的末尾写入一个字符。这不是你描述的问题。
  • 抱歉我的建议(不要在客户端代码中创建文件)没有帮助。我已删除答案,以便您获得更多关注。
  • 两个程序的“当前”文件夹是否相同? FIFO文件名上没有路径(例如/tmp/american_maid
  • 不,它们在同一个目录中(客户端、服务器和 American_maid fifo)
  • 检查您的open() 呼叫是否有效。请注意,如果您在客户端读取 300 个字节,则写入 s[num] 会超出数组末尾;它可能会弄乱读取的数据字节数。

标签: c client-server named-pipes fifo mkfifo


【解决方案1】:

当我使用命令序列运行下面显示的代码时:

$ ln -s server.c out.txt
$ ./client &
$ ./server
$

我得到了客户端程序打印的源代码的副本。同样,当我使用以下命令运行命令时:

$ ./server &
$ ./client
$

修改后的代码并没有太大的修改。它避免了do { } while(...) 循环——它们很少真正有益——并且非常小心不要溢出缓冲区。该代码还删除了多余的标头。

server.c

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

int main(void)
{
    const char infile[] = "out.txt";
    FILE *fp = fopen(infile, "r");

    if (fp == 0)
    {
        fprintf(stderr, "Failed to open %s for reading", infile);
        return(1);
    }

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for readers...\n");
    int fd = open(FIFO_NAME, O_WRONLY);
    if (fd > 0)
    {
        char line[300];
        printf("got a reader--type some stuff\n");

        while (fgets(line, sizeof(line), fp))
        {
            int len = strlen(line);
            int num = write(fd, line, len);
            if (num != len)
                perror("write");
            else
                printf("speak: wrote %d bytes\n", num);
        }
        close(fd);
    }

    fclose(fp);

    return 0;
}

client.c

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

#define FIFO_NAME "american_maid"

int main(void)
{
    const char outfile[] = "client.out";
    FILE *fp = fopen(outfile, "w");

    if (fp == 0)
    {
        fprintf(stderr, "Failed to open %s for writing\n", outfile);
        return 1;
    }

    printf("waiting for writers...\n");
    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    int fd = open(FIFO_NAME, O_RDONLY);
    if (fd > 0)
    {
        int num;
        char s[300];
        printf("got a writer\n");

        while ((num = read(fd, s, sizeof(s))) > 0)
        {
            printf("tick: read %d bytes: \"%.*s\"\n", num, num, s);
            fprintf(fp, "%.*s", num, s);
        }

        close(fd);
    }
    fclose(fp);

    return 0;
}

请注意,此版本将其输出写入文件client.out;即使给定一个需要处理很长行的文件(2049 字节,包括末尾的换行符),client.out 中的输出与out.txt 中的输入完全匹配。

【讨论】:

    【解决方案2】:

    从文件client.c 中删除行mknod(FIFO_NAME, S_IFIFO | 0666, 0);。然后程序将按预期工作。服务器将创建一个文件并将文件内容发送给fifo。

    【讨论】:

    • 已经做了,没有帮助(我在客户端代码中注释了这一行后问题是一样的)
    • 实际上,让两个程序都尝试创建完全相同的文件并不是一件坏事,这意味着任何一个都可以先启动——而忽略 mknod 返回意味着他可以在那里创建一个常规文件。在这种情况下,这并不常见,但也不错。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-16
    相关资源
    最近更新 更多