简体   繁体   中英

“Bad file descriptor” when accessing socket descriptor in child thread

When trying to access socket descriptor (with bind() or listen()) in a child thread I get the error:

Bad file descriptor

Here is the code (headers ignored):

class task {
private:
    std::int32_t        socFd;
    std::string         path;
    char                buffer[MAX_SOC_BUFFER];
    struct sockaddr_un  socAddr;

public:
    void init() {
        if ((socFd = socket((std::int32_t)AF_UNIX, (std::int32_t)SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(1);
        }

        socAddr.sun_family = AF_UNIX;
        strcpy(socAddr.sun_path, getSocPath().c_str());
    }

    task(const std::string& path) : path{path}
    {
        init();
    }

    auto getSocketFd() ->decltype(socFd) {
        return socFd;
    }

    const std::string& getSocPath() {
        return path;
    }

    auto getSocAddr() -> decltype(socAddr)&
    {
        return socAddr;
    }

    char* getBuff() {
        return buffer;
    }

    virtual ~ task() {
        close(getSocketFd());
    }
};


class server_task : public task{
public:
    void init () {
        ::unlink(getSocPath().c_str());
        size_t len = sizeof(getSocAddr());
        if (bind(getSocketFd(), (struct sockaddr *)&(getSocAddr()), len) == -1) {
            perror("bind");
            exit(1);
        }
    }

    server_task(const std::string& path) : task(path)
    {
        init();
    }

    void operator()() {
        struct sockaddr_un remote;
        if (listen(getSocketFd(), 5) == -1) {
            perror("listen");
            exit(1);
        }
        for(;;) {
            int done, n, socFd2;
            printf("Waiting for a connection...\n");
            socklen_t t = sizeof(remote);
            if ((socFd2 = accept(getSocketFd(), (struct sockaddr *)&remote, &t)) == -1) {
                perror("accept");
                exit(1);
            }
            printf("Connected.\n");
            done = 0;
            do {
                n = recv(socFd2, getBuff(), 100, 0);
                if (n <= 0) {
                    if (n < 0) perror("recv");
                    done = 1;
                }
                if (!done) {
                    std::string buffStr(getBuff());
                    std::transform(buffStr.begin(), buffStr.end(),buffStr.begin(), ::toupper);
                    if (send(socFd2, buffStr.c_str(), n, 0) < 0) {
                        perror("send");
                        done = 1;
                    }
                }
            } while (!done);
            close(socFd2);
        }
    }
};


int main(){
std::vector<std::thread> threads;
server_task server("/tmp/temp_socket");
threads.push_back(std::thread(server));

for(auto& thread : threads)
    thread.join();

return 0;

}

If I change the main() function to:

int main(){
    server_task server("/tmp/temp_socket");
    server();
    return 0;
}

no such error occurs. As I understand the file descriptor table are shared between parent process and it's children threads so the socket handle should be valid.

What am I doing wrong?

threads.push_back(std::thread(server));

This creates at least one copy of the server object, maybe multiple copies, and because you haven't defined a copy constructor every copy shares the same socket and the first one to go out of scope closes the socket. By the time the new thread starts the temporary copies have been destroyed and closed the socket, so the copy of the server_task that runs in the new thread refers to a closed socket.

You should either define a move constructor for your task and server_task types so that ownership of the socket is transferred not copied, and move the object into the thread:

thread.push_back(std::thread(std::move(server)));

or else you should pass the server to the new thread by reference so there are no copies:

thread.push_back(std::thread(std::ref(server)));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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