C语言 管道集fd具有与套接字接受函数相同的文件描述符

mpgws1up  于 2023-05-28  发布在  其他
关注(0)|答案(1)|浏览(153)

提问

当我想使用fork()函数创建子进程来获取socket聊天组时,使用pipe传递name,ip等。但是pipe(fd)设置了相同的文件描述符(fd[1] = 4, socket fd = 4)。因此,如果我想write(fd[1], ....)将传递给socket fd(4)
如何避免或解决这个问题?

代码

服务器

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <setjmp.h>

#define SERVER_PORT 9098
#define MAX_OR_ADD_LENGTH 100
#define MAX_NAME_SIZE 40
#define MAX_IP_SIZE 20

struct socket_ip_name{
    int socket_fd;
    char *ip;
    char *name;
    struct socket_ip_name *prev;
    struct socket_ip_name *next;
};

struct record{
    int current_length;
    struct socket_ip_name *head;
    struct socket_ip_name *tail;
    int ADDED_LENGTH;
    int max_fd_p;
};

struct fd_message{
    char message_type[7];
    char name[MAX_NAME_SIZE];
    char ip[MAX_IP_SIZE];
    int socket_fd;
};

jmp_buf for_e;

void initialized_record(struct record *);
void free_record(struct record *);

int main(void){
    int fd[2];
    if(pipe(fd) == -1){
        perror("create pipe error");
    }
    printf("fd[0] is %d, fd[1] is %d\n", fd[0], fd[1]);
    pid_t pid;
    int server_fd = socket(AF_INET, SOCK_STREAM, 0), client_fd;
    struct record records;
    int max_fd_p = 0;
    // initialized
    initialized_record(&records);
    // create
    if(server_fd == -1){
        perror("create socket descriptor error:");
        exit(-1);
    }
    char message[1024];
    struct sockaddr_in server_addr, client_addr;
    socklen_t len = sizeof(client_addr);
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_family = AF_INET;
    if(inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) != 1){
        perror("alloc address error");
        exit(-1);
    }
    if(bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0){
        perror("bind error:");
        exit(-1);
    }
    listen(server_fd, 1000);
    //
    while (1){
        client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len);
        inet_ntop(AF_INET, &client_addr.sin_addr, message, sizeof(message));
        if((pid = fork()) == -1){
            perror("fork error");
            break;
        }else if(pid == 0){
            close(fd[0]);
            close(server_fd);
            printf("pipe fd is %d, and socket fd is %d\n", fd[1], client_fd);
            printf("Chat subprocess exit\n");
            exit(0);
        }else{
            close(fd[1]);
            close(client_fd);
            waitpid(pid, NULL, WNOHANG);
        }
    }
    // free function
    free_record(&records);
    close(server_fd);
    exit(0);
}

void initialized_record(struct record *_record){
    _record->ADDED_LENGTH = MAX_OR_ADD_LENGTH;
    _record->current_length = 0;
    _record->head = NULL;
    _record->tail = NULL;
    _record->max_fd_p = 0;
}

struct socket_ip_name *initialized_sin(int socket_fd, char *ip){
    struct socket_ip_name * sin = malloc(sizeof(struct socket_ip_name));
//    printf("init state ad ip is %s\n", ip);
    sin->socket_fd = socket_fd;
    sin->ip = malloc(sizeof(char) * strlen(ip));
    if(sin->ip == NULL){
        exit(-1);
    }
    strcpy(sin->ip, ip);
    sin->name = NULL;
    sin->prev = NULL;
    sin->next = NULL;
    return sin;
}

void free_record(struct record *_record){
    struct socket_ip_name *for_free_pointer = _record->head;
    while (_record->head){
        _record->head = _record->head->next;
        free(for_free_pointer->name);
        free(for_free_pointer->ip);
        free(for_free_pointer);
        for_free_pointer = _record->head;
    }
    _record->tail = NULL;
    _record->current_length = 0;
    _record->max_fd_p = 0;
}

客户端

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define SERVER_PORT 9098

int main(void){
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(client_fd == -1){
        perror("create socket error");
        exit(-1);
    }
    struct sockaddr_in client_addr;
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(SERVER_PORT);
    if(inet_pton(AF_INET, "127.0.0.1", &client_addr.sin_addr) == -1){
        perror("address error:");
        exit(-1);
    }
    if(connect(client_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)) == -1){
        perror("connect error");
        exit(-1);
    }
    char message[1024], input_message[1024];
    ssize_t n;
    printf("input your name:");
    fgets(input_message, 1024, stdin);
    if(write(client_fd, input_message, 1024) == -1){
        perror("write error");
    }
    while (1){
        memset(message, 0, sizeof(message));
        if((n = read(client_fd, message, 1024)) != -1){
            if (n == 0){
                printf("Get Fin cause from server\n");
                break;
            }
            message[n] = 0;
            printf("[server]: %s\n", message);
        }
        memset(message, 0, sizeof(message));
        printf("input message you want to send:");
        if(fgets(input_message, 1024, stdin) == NULL){
            char *end_message;
            if(feof(stdin)){
                end_message = "End of file reached\n";
            }else{
                end_message = "Error occurred\n";
            }
            if(write(client_fd, end_message, 1024) == -1){
                perror("write error");
            }
            close(client_fd);
            break;
        }
        if(write(client_fd, input_message, 1024) == -1){
            perror("write error");
        }

    }
}

截图

bihw5rsg

bihw5rsg1#

在父节点中调用了close(fd[1]);(在第一个请求的末尾),释放了fd 4。
要与每个子节点独立通信,您需要为每个子节点使用一个管道。管道应该在循环中创建(在fork之前)。
下一个问题是,您需要同时侦听传入的连接和传入的数据。为此,您需要使用select或类似的。
请注意,父级永远不会关闭管道的读端。它需要这样做,因为管道只有在所有 * 四个 * 描述符都关闭后才会关闭。

相关问题