Linux套接字程序管道故障排查:子父进程管道通信异常
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
sprintfUsage: This line is dangerous and incorrect:buffer[BUF_SIZE] = sprintf(buffer,"Upload bude trvat %d:%d:%d\n",hours,minutes,seconds);sprintfreturns the number of characters written, and you're assigning it tobuffer[BUF_SIZE]—which is out of bounds (arrays are 0-indexed, so the last valid index isBUF_SIZE-1). Just callsprintfnormally 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 plainwait()can lead to zombie processes and doesn't guarantee you're waiting for the specific child you just forked. Usewaitpid(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 withhtons(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
- Added
pipe(fd)before forking to properly initialize the pipe communication channel. - Fixed buffer overflow issues with
sprintfand optimizedsend()calls to only send necessary data. - Ensured port numbers use network byte order with
htons(). - Used
waitpid()to safely wait for the child process and avoid zombies. - Fixed file descriptor lifecycle (closing unused ends of the pipe and client socket at the right time).
- 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

