简体   繁体   English

C 在不同线程上的 sockets 上使用 accept() 时出现错误的文件描述符问题

[英]C Bad file descriptor issue when using accept() on sockets that is on different threads

What you are trying to do:您正在尝试做的事情:

Hello, I'm rewriting a old legacy custom http server used on a website.您好,我正在重写网站上使用的旧式自定义 http 服务器。

What's the issue:有什么问题:

When accept is called, Can't accept client: bad file descriptor error will be outputted to the terminal even though code looks correct.调用 accept 时,Can't accept client: bad file descriptor 错误将输出到终端,即使代码看起来正确。

What you tried:你尝试了什么:

  • changed orders of stuff改变了东西的顺序
  • I decided that my boilerplate has hidden errors can't be seen so I copied boilerplate from a random website on the internet but Im not satisfied with that so I returned back to my own code.我决定我的样板文件隐藏了无法看到的错误,所以我从互联网上的一个随机网站复制了样板文件,但我对此不满意,所以我回到了我自己的代码。

Code:代码:

#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

// This version of software is licensed under public domain feel free to use for any purpose
typedef struct{
    char* http_path;
    void (*function);
} location;
unsigned short server_count = 0;

/*
 * typedef struct is bad practice especially by linux convention which i try to
 * follow but for some reason program will compile or fail randomly and typedef
 * struct fixes it for some reason
*/
typedef struct{
    unsigned char running;
    unsigned id;
    unsigned locationCount;
    location* locations;
    unsigned port;    
} http_server_t;
http_server_t* servers;

char nServer(unsigned short port) {
    server_count++;
    char status = server_count;
    // The warning happens here can be disregarded
    if(server_count == 1) {
        status = (servers = malloc(sizeof(servers)*server_count));
    }else{
        status = (realloc(servers, sizeof(servers)*server_count));
    }
    if(!status){
        return -1;
    }
    servers[server_count].port = port;
    servers[server_count].running = 1;
    servers[server_count].locations = sizeof(servers[server_count].locations)*servers[server_count].locationCount+1;
    return server_count;

    
}
typedef struct __attribute__((packed)) {
    unsigned sock;
    struct sockaddr* addr;
    struct sockaddr_in inf;
} serverHandlerData;

void serveClient() {

}
void socketHandle(void* data) {
    // lazy to properly name these stuff
    // FIXME: Refactor the code here

    
   
    
    serverHandlerData *fixed = data;
    unsigned sock = fixed->sock; struct sockaddr* addr = fixed->addr;
    struct sockaddr_in in = fixed->inf;

    if(bind(sock, (struct sockaddr *)&in, sizeof(struct sockaddr))) {
        perror("Can't bind");
        return;
    } 

    if((listen(sock, 0)) < 0) {
        perror("Can't listen the socket");
        return;
    }        



    for(;;) {
        int csock;
        struct sockaddr_in caddr;
        if((csock = accept(csock, (struct sockaddr*)&caddr, (socklen_t)sizeof(struct sockaddr))) < 0) {
            perror("Can't accept client");
            return;
        }

        unsigned char* buffer = malloc(100);
        read(csock, buffer, 100);
        printf(buffer);
        close(csock);
    }
    

}
void iServers() {
    for(unsigned long x = 1; x < server_count; x++) {
        struct sockaddr_in addr;
        unsigned char status = 0;
        unsigned int sock = 0;
        if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            perror("Socket can't be made due a error");
            return;
        }
        printf("%d", servers[x].port);

        memset(&addr, 0, sizeof(addr));
        // ipv4
        


        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(servers[x].port);
        /*if((setsockopt(sock, (struct sockaddr*)&addr, SO_REUSEADDR,
                     SO_BROADCAST, (struct socklen_t*)sizeof(SO_BROADCAST))) < 0){
                        perror("Failure while setting socket options");
                        return;
        }      */  
        serverHandlerData s;
        s.sock = sock;
        s.addr = (struct sockaddr*)&addr;
        s.inf = addr;


        pthread_t serverHandle;

        pthread_create(&serverHandle, NULL, socketHandle, &s);
        pthread_join(serverHandle, NULL);
    }
}

unsigned char running = 1;

void ctrlCHandler(){
    running = 0;
}
int main() {
    nServer(4080);
    // FIXME: Second server never gets toggled on
    nServer(1010);

    //nServer(80);

    iServers();
    return 0;
}

Minimal example?最小的例子? I do not know what exactly triggers the error so I can't create a minimal reproducable example.我不知道究竟是什么触发了错误,所以我无法创建一个最小的可重现示例。

IMHO, the problem is that you have requested恕我直言,问题是您已要求

listen(sock, 0); /* BAD */

as this sets the incoming backlog queue to 0 entries, dissalowing connection establishment.因为这会将传入的积压队列设置为 0 个条目,从而禁止建立连接。 The normal call should be (to behave as it used to)正常的呼叫应该是(表现得像以前一样)

listen(sock, 5); /* OK */

that allows up to 5 connect requests before starting to reject connections.在开始拒绝连接之前最多允许 5 个连接请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM