c - C 中的进程间通信

标签 c process pipe ipc

我正在使用管道进行 IPC 练习。协议(protocol)如下:

  1. 客户端(子)从标准输入读取文件名
  2. 客户端通过管道将文件名发送到服务器
  3. 服务器(父级)从管道读取文件名
  4. 服务器获取有关文件的信息(stat sys 调用)
  5. 服务器通过管道将文件信息发送到客户端。
  6. 客户端从管道读取文件信息并输出到标准输出

我在最后的步骤中遇到问题,我不知道如何正确发送此信息。目前客户端的输出是垃圾。这是代码:

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

#define BUFSIZE 1024

int main()
{
    int fd1[2], fd2[2], pid, n;
    char buf[BUFSIZE];
    pipe(fd1);
    pipe(fd2);
    if ((pid = fork()) == 0)
    {
        close(fd1[0]);
        close(fd2[1]);
        read(STDIN_FILENO, buf, BUFSIZE); // 1. client(child) reads file name from stdin
        int len = strlen(buf);
        buf[len - 1] = '\0';
        write(fd1[1], buf, len); // 2. client sends file name over pipe to server
        while ((n = read(fd2[0], buf, BUFSIZE)) > 0)
        {
            write (STDOUT_FILENO, buf, n); // 6. client reads file info from pipe and outputs to stdout
        }
    }
    else
    {
        struct stat st;
        close(fd1[1]);
        close(fd2[0]);
        read(fd1[0], buf, BUFSIZE); // 3. server (parent) reads file name from pipe
        stat(buf, &st); // 4. server obtains information about the file (stat sys call)
        write(fd2[1], (void *)st.st_size, sizeof(st.st_size)); // 5. server file information over pipe to client.
        write(fd2[1], (void *)st.st_atime, sizeof(st.st_atime));
    }
    return 0;
}

更新:

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

#define BUFSIZE 1024

int main()
{
    int fd1[2], fd2[2], pid;
    size_t n;
    char buf[BUFSIZE];
    pipe(fd1);
    pipe(fd2);
    if ((pid = fork()) == 0)
    {
        close(fd1[0]);
        close(fd2[1]);
        n = read(STDIN_FILENO, buf, BUFSIZE - 1); // 1. client(child) reads file name from stdin
        buf[n] = '\0';
        write(fd1[1], buf, n); // 2. client sends file name over pipe to server
        while ((n = read(fd2[0], buf, BUFSIZE)) > 0)
        {
            if ((write (STDOUT_FILENO, buf, n)) != n) // 6. client reads file info from pipe and outputs to stdout
            {
                perror("client: write error\n");
            }
        }
    }
    else
    {
        struct stat st;
        close(fd1[1]);
        close(fd2[0]);
        read(fd1[0], buf, BUFSIZE); // 3. server (parent) reads file name from pipe
        stat(buf, &st); // 4. server obtains information about the file (stat sys call)
        if (write(fd2[1], (void *)st.st_size, sizeof(st.st_size)) != sizeof(st.st_size)) // 5. server sends file information over pipe to client
        {
            perror("server: write error\n");
        } 
        if (write(fd2[1], (void *)st.st_atime, sizeof(st.st_atime)) != sizeof (st.st_atime))
        {
            perror("server: write error\n");
        }
    }
    return 0;
}

最佳答案

这里不能使用strlen()。您应该使用 read() 的返回值。

read()之后,buf中的数据只不过是一个字节序列,如果添加'\0'<,它可能会变成字符串 序列末尾的字节。由于它不存在,调用 strlen() 会调用未定义的行为,因此无论您之后做什么,它都不会按预期运行。

strlen() 可以被认为是

size_t 
strlen(const char *const string)
{
    size_t length;
    length = 0;
    while (string[length] != '\0')
        ++length;
    return length;
}

你应该避免这样的事情的一个原因

for (size_t i = 0 ; i < strlen(string) ; ++i) ...

特别是因为您可以使用类似于上面 strlen() 实现中的循环。

使用 read() 的返回值来代替

ssize_t read_length;
read_length = read(STDIN_FILENO, buf, sizeof(buf) - 1);

如果您想使其成为有效字符串,可以将其传递给任何 str* 函数,只需

buf[read_length] = '\0';

不要忘记检查错误,例如read_length != -1

关于c - C 中的进程间通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37516249/

相关文章:

c - fgets 在 gdb 下遇到段错误,但在正常运行时不会遇到

c - 如何在 vb.net 中获取图像的句柄

c# - 服务中的定时器

unix - unix fork exec 序列真的像听起来那么昂贵吗?

c - C 中的多进程、 fork 和管道

linux - 检索存储在 Linux 匿名 PIPE 的 "write"结尾的字节数

c++ - 如何在 PC/Visual C++ 上查明指针是否在堆栈上

c - 在 c sharp 中调整自定义窗体的大小(带有阴影效果)和鼠标拖动事件的控件?

process - 难以理解 fork 逻辑

c 编程 - 一位 parent 和 4 个 child 之间的双向沟通​​没有结果