【问题标题】:Multi Child Processes to read when One parent Process write some string in C language当一个父进程用C语言编写一些字符串时要读取的多个子进程
【发布时间】:2021-02-28 22:18:14
【问题描述】:

我正在编写具有 1 个父进程和 3 个子进程的回显服务器。这个服务器的目的是……

  1. 由函数 fork() 创建的每个子进程都会从每个客户端接收一个字符串。
  2. 父进程应连接 3 个字符串并发送每个子进程。
  3. 每个进程都必须将由父进程连接起来的字符串发送给每个客户端。

我尝试过使用 fork、pipe、read 和 write 函数。
我做了两个管道来在孩子和父母之间进行交流。每个子进程都会使用 write 函数来传递一个字符串。为了接收父进程连接的字符串,我编写了源代码

编译执行后发现逻辑错误,只有一个客户端,第一次执行,收到连接字符串,其余两个客户端显示消息“Connection reset by peer”。

我在使用读写函数后关闭了所有管道。我不知道如何处理这个问题。

如何让3个客户端都能正确接收到服务器发送的字符串?

我将附上源代码。

  • 服务器代码
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>
#define MAXLINE 1024
#define PORTNUM 3600

int main(int argc, char **argv)
{
    int p1[2];
    int p2[2];

    pipe(p1);
    pipe(p2);
    int index = 0;
    //char channel[100];
    char full_str[MAXLINE];
    char recv[MAXLINE];
    int isOK1 = 0;
    int isOK2 = 0;

    int listen_fd, client_fd;
    pid_t pid;
    socklen_t addrlen;
    int readn;
    char buf[MAXLINE];
    struct sockaddr_in client_addr, server_addr;

    if( (listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        return 1;
    }
    memset((void *)&server_addr, 0x00, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(PORTNUM);

    if(bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) ==-1)
    {
        perror("bind error");
        return 1;
    }
    if(listen(listen_fd, 5) == -1)
    {
        perror("listen error");
        return 1;
    }

    signal(SIGCHLD, SIG_IGN);
    while(1)
    {
        addrlen = sizeof(client_addr);
        client_fd = accept(listen_fd,
            (struct sockaddr *)&client_addr, &addrlen);
        if(client_fd == -1)
        {
            printf("accept error\n");
            break;
        }
        pid = fork();
        if(pid == 0)
        {
            close( listen_fd );
            close(p1[0]);
            close(p2[1]);
            memset(buf, 0x00, MAXLINE);
            while((readn = read(client_fd, buf, MAXLINE)) > 0)
            {
                printf("Read Data %s(%d) : %s\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port, buf);
                
                write(p1[1], buf, strlen(buf));
                close(p1[1]);
                wait(NULL);

                isOK2 = read(p2[0], recv, MAXLINE);
                
                // When recv read concatenated string by p2 pipe, read function would be executed.
                if(isOK2 > 0){
                    printf("%s I am over\n", recv);
                    write(client_fd, recv, MAXLINE);
                
                    close(p2[0]);
                    exit(1);
                    
                }

                memset(buf, 0x00, MAXLINE);
            }
            close(client_fd);
            return 0;
        }
        else if( pid > 0) {
            close(p1[1]);
            close(p2[0]);

            char channel[100];
            if((isOK1 = read(p1[0], channel, 100)>0)){
                    close(p1[0]);
    
                    strcat(full_str, channel);
                    index++;
                    full_str[strlen(full_str)] = '\0';  
                    printf("%d \n", index); 
                    printf("%s \n", channel);
                    printf("%ld \n", strlen(channel));
                    if(index >= 3) {
                        write(p2[1], full_str, strlen(full_str));
                        close(p2[1]);
                        exit(0);
                    }
                    
                    memset(channel, 0x00, 100);
                
            }
            //wait(NULL);
        }
        close(client_fd);
        
    }
    return 0;
}
  • 客户代码
#include <sys/socket.h>  
#include <arpa/inet.h>   
#include <sys/stat.h>
#include <stdio.h>      
#include <string.h>    
#include <unistd.h>     

#define MAXLINE    1024

int main(int argc, char **argv)
{
    struct sockaddr_in serveraddr;
    int server_sockfd;
    int client_len;
    char buf[MAXLINE];

    if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    {
        perror("error :");
        return 1;
    }

    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serveraddr.sin_port = htons(3600);

    client_len = sizeof(serveraddr);

    if (connect(server_sockfd, (struct sockaddr *)&serveraddr, client_len)  == -1)
    {
        perror("connect error :");
        return 1;
    }

    memset(buf, 0x00, MAXLINE);
    read(0, buf, MAXLINE);    
    buf[strlen(buf)-1] = '\0'; // trim text
    if (write(server_sockfd, buf, MAXLINE) <= 0)
    {
        perror("write error : ");
        return 1;
    }
    memset(buf, 0x00, MAXLINE);

    if (read(server_sockfd, buf, MAXLINE) <= 0)
    {
        perror("read error : ");
        return 1;
    }
    printf("read : %s\n", buf);
    close(server_sockfd);
    return 0;
}

【问题讨论】:

    标签: c pipe fork


    【解决方案1】:

    您不想为此使用“管道”和“叉子”。 您提到您已经“尝试”使用这些功能,这可能意味着您认为这是一个好方法,但不,不是。

    你应该使用'select'或'poll',这样你可以在一个线程中处理它。

    服务器

    • 创建服务器套接字、绑定和监听
    • 接受直到所有客户端都连接
    • 执行轮询/选择读取(在客户端 fd 上),直到读取所有字符串
    • 连接字符串
    • 执行轮询/选择写入(在客户端 fd 上)直到写入字符串
    • 全部关闭

    客户

    • 创建套接字
    • 连接到服务器
    • 在写入或读取字符串之前执行轮询/选择以进行读取/写入
    • 关闭套接字

    如果您想要多线程,请使用线程而不是“fork”。这样做的原因是,您可以在父进程和子进程之间共享内存,并且无需管道(以及额外的读写)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-27
      • 1970-01-01
      • 2017-04-15
      • 2014-05-11
      • 2017-09-19
      • 1970-01-01
      • 1970-01-01
      • 2021-08-20
      相关资源
      最近更新 更多