You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux套接字程序管道故障排查:子父进程管道通信异常

Fixing Your Pipe Communication Issue in the Socket Server

Let's break down what's going wrong with your pipe setup and fix all the related bugs step by step:

Critical Root Cause: Pipe is Never Initialized

The biggest issue here is that you declared the pipe file descriptor array int fd[2]; but never called pipe(fd) to create the actual pipe. Without this system call, fd[0] and fd[1] are uninitialized garbage values—so any write() or read() on them will fail immediately, which explains why you're seeing both "write error" and "read error" messages, plus a garbage/0 value for hours.

You need to create the pipe before forking the child process, so both parent and child inherit valid, connected file descriptors.

Other Bug Fixes That Matter

Beyond the pipe issue, there are several smaller problems breaking your code:

  • Invalid sprintf Usage: This line is dangerous and incorrect:
    buffer[BUF_SIZE] = sprintf(buffer,"Upload bude trvat %d:%d:%d\n",hours,minutes,seconds);
    
    sprintf returns the number of characters written, and you're assigning it to buffer[BUF_SIZE]—which is out of bounds (arrays are 0-indexed, so the last valid index is BUF_SIZE-1). Just call sprintf normally without the assignment.
  • Misplaced close(newsockfd): The parent was closing the client socket immediately after forking, but the child still needs this socket to communicate with the client. Move this close operation until after the parent has waited for the child to finish.
  • Unsafe wait() Call: Using plain wait() can lead to zombie processes and doesn't guarantee you're waiting for the specific child you just forked. Use waitpid(childpid, NULL, 0) instead.
  • Network Byte Order Port: You set addr.sin_port = PORT; directly—you need to convert the port to network byte order with htons(PORT) for cross-platform compatibility.
  • Missing Headers: Several required headers (like <sys/wait.h> and <unistd.h>) were missing, which could cause compilation warnings or errors.

Corrected Full Code

#define PORT 4444
#define BUF_SIZE 2000
#define CLADDR_LEN 100
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>

void func(int subor,int rychlost,int *h,int *m,int *s){
    int hours,minutes,seconds,inputSecond;
    int remainingSeconds;
    int secondsInHour = 60 * 60;
    int secondsInMinute = 60;
    subor *= 8000;
    rychlost *= 1000;
    inputSecond = subor/rychlost;
    hours = (inputSecond/secondsInHour);
    remainingSeconds = inputSecond - (hours * secondsInHour);
    minutes = remainingSeconds/secondsInMinute;
    remainingSeconds = remainingSeconds - (minutes*secondsInMinute);
    seconds = remainingSeconds;
    *h=hours;
    *m=minutes;
    *s=seconds;
}

int main() { // Standard C requires main to return int
    struct sockaddr_in addr, cl_addr;
    int sockfd, len, ret, newsockfd,fileSize,speed;
    char buffer[BUF_SIZE]="Type 'start' or 'exit'\n";
    pid_t childpid;
    int hours,minutes,seconds;
    int fd[2];

    // Create pipe BEFORE forking to share descriptors with child
    if (pipe(fd) == -1) {
        perror("pipe failed");
        exit(EXIT_FAILURE);
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Error creating socket");
        exit(EXIT_FAILURE);
    }
    printf("Socket created...\n");

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(PORT); // Convert port to network byte order

    ret = bind(sockfd, (struct sockaddr *) &addr, sizeof(addr));
    if (ret < 0) {
        perror("Error binding");
        exit(EXIT_FAILURE);
    }
    printf("Binding done...\n");
    printf("Waiting for a connection...\n");

    listen(sockfd, 5);

    for (;;) {
        len = sizeof(cl_addr);
        newsockfd = accept(sockfd, (struct sockaddr *) &cl_addr, &len);
        if (newsockfd < 0) {
            perror("Error accepting connection");
            exit(EXIT_FAILURE);
        }
        printf("Connection accepted...\n");

        if ((childpid = fork()) == 0) {
            // Child: close unused read end of pipe and listening socket
            close(fd[0]);
            close(sockfd);

            // Send only the actual string length, not full buffer
            ret = send(newsockfd, buffer, strlen(buffer) + 1, 0);
            if (ret < 0) {
                perror("Error sending data");
                exit(EXIT_FAILURE);
            }

            for (;;) {
                memset(buffer, 0, BUF_SIZE);
                ret = recv(newsockfd, buffer, BUF_SIZE, 0);
                if(ret < 0) {
                    perror("Error receiving data");
                    exit(EXIT_FAILURE);
                }
                if (strcmp(buffer, "start\n") == 0) {
                    ret = send(newsockfd, "Type size of file in [Mb]\n", strlen("Type size of file in [Mb]\n") + 1, 0);
                    if (ret < 0) {
                        perror("Error sending data");
                        exit(EXIT_FAILURE);
                    }

                    memset(buffer, 0, BUF_SIZE);
                    ret = recv(newsockfd, buffer, BUF_SIZE, 0);
                    if(ret < 0) {
                        perror("Error receiving data");
                        exit(EXIT_FAILURE);
                    }
                    fileSize = atoi(buffer);

                    ret = send(newsockfd, "Type Speed of internet in [MB]\n", strlen("Type Speed of internet in [MB]\n") + 1, 0);
                    if (ret < 0) {
                        perror("Error sending data");
                        exit(EXIT_FAILURE);
                    }

                    memset(buffer, 0, BUF_SIZE);
                    ret = recv(newsockfd, buffer, BUF_SIZE, 0);
                    if(ret < 0) {
                        perror("Error receiving data");
                        exit(EXIT_FAILURE);
                    }
                    speed = atoi(buffer);

                    func(fileSize,speed,&hours,&minutes,&seconds);

                    // Fixed sprintf usage
                    sprintf(buffer,"Upload bude trvat %d:%d:%d\n",hours,minutes,seconds);
                    ret = send(newsockfd, buffer, strlen(buffer) + 1, 0);
                    if (ret < 0) {
                        perror("Error sending data");
                        exit(EXIT_FAILURE);
                    }

                    // Write hours to pipe
                    if(write(fd[1], &hours, sizeof(int)) == -1){
                        perror("write error");
                        exit(EXIT_FAILURE);
                    }
                    close(fd[1]); // Close write end after writing
                    exit(EXIT_SUCCESS);
                }
            }
        } else {
            // Parent: close unused write end of pipe
            close(fd[1]);
            int fin;

            // Wait for the specific child to finish
            waitpid(childpid, NULL, 0);

            // Read hours from pipe
            if(read(fd[0], &fin, sizeof(int)) == -1){
                perror("read error");
                exit(EXIT_FAILURE);
            }
            printf("Received hours from child: %d\n", fin);
            close(fd[0]);
        }
        // Close client socket only after child is done using it
        close(newsockfd);
    }
    return 0;
}

Key Improvements Recap

  1. Added pipe(fd) before forking to properly initialize the pipe communication channel.
  2. Fixed buffer overflow issues with sprintf and optimized send() calls to only send necessary data.
  3. Ensured port numbers use network byte order with htons().
  4. Used waitpid() to safely wait for the child process and avoid zombies.
  5. Fixed file descriptor lifecycle (closing unused ends of the pipe and client socket at the right time).
  6. Added missing headers and corrected main() return type to follow C standards.

With these changes, your pipe will work as expected, and you'll see the actual calculated hours value printed instead of 0.

内容的提问来源于stack exchange,提问作者Sean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:28:24