Сокет сервера Linux - неправильный дескриптор файла

У меня проблема с сокетом сервера под Linux. По неизвестной мне причине пропадает сокет сервера и я получаю Bad file descriptor ошибка в вызове выбора, ожидающего входящего соединения. Эта проблема всегда возникает, когда я закрываю несвязанное соединение сокета в другом потоке. Это происходит на встроенном Linux с ядром 2.6.36.

Кто-нибудь знает, почему это произойдет? Это нормально, что сокет сервера может просто исчезнуть, что приводит к Bad file descriptor?

редактировать: другой код сокета реализует VNC-сервер и работает в совершенно другом потоке. Единственное, что особенного в этом другом коде - это использование setjmp/longjmp но это не должно быть проблемой.

Код, который создает сокет сервера, следующий:

int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(1234);

const int optionval = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &optionval, sizeof(optionval));

if (bind(server_socket, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
    perror("bind");
    return 0;
}

if (listen(server_socket, 1) < 0) {
    perror("listen");
    return 0;
}

Я жду входящего соединения, используя код ниже:

static int WaitForConnection(int server_socket, struct timeval *timeout)
{
    fd_set read_fds;

    FD_ZERO(&read_fds);
    int max_sd = server_socket;
    FD_SET(server_socket, &read_fds);

    // This select will result in 'EBADFD' in the error case.
    // Even though the server socket was not closed with 'close'.
    int res = select(max_sd + 1, &read_fds, NULL, NULL, timeout);
    if (res > 0) {
        struct sockaddr_in caddr;
        socklen_t clen = sizeof(caddr);
        return accept(server_socket, (struct sockaddr *) &caddr, &clen);
    }

    return -1;
}

редактировать: когда возникает проблема, я просто перезагружаю сервер, но я не понимаю, почему идентификатор сокета сервера должен внезапно стать неверным дескриптором файла:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (server_socket, SOL_SOCKET, SO_ERROR, &error, &len );
if (retval < 0) {
    close(server_socket);
    goto server_start;
}

4 ответа

Сокеты (файловые дескрипторы) обычно страдают от тех же проблем управления, что и необработанные указатели в C, Всякий раз, когда вы закрываете сокет, не забудьте назначить -1 к переменной, которая содержит значение дескриптора:

close(socket);
socket = -1;

Как бы вы сделали, чтобы C указатель

free(buffer);
buffer = NULL;

Если вы забудете это сделать, вы сможете позже дважды закрыть сокет, как free() памяти в два раза, если это был указатель.

Другая проблема может быть связана с тем, что люди обычно забывают: файловые дескрипторы в среде UNIX начинаются с0, Если где-то в коде у вас есть

struct FooData {
    int foo;
    int socket;
    ...
}

// Either
FooData my_data_1 = {0};
// Or
FooData my_data_2;
memset(&my_data_2, 0, sizeof(my_data_2));

В обоих случаях my_data_1 а также my_data_2 иметь действительный дескриптор (socket) значение. А потом какой-то кусок кода, отвечающий за освобождение FooData структура может слепо close() этот дескриптор, который оказывается слушающим сокетом вашего сервера (0).

1- закройте ваше гнездо:

close(sockfd);

2 - очистить дескриптор файла сокета от выбранного набора:

FD_CLR(sockfd,&master); //opposite of FD_SET

Вы не различаете два случая ошибок в вашем коде, оба могут потерпеть неудачу select или же accept, Я думаю, что у вас просто есть тайм-аут, и этот выбор возвращает 0,

  • Распечатать retval а также errno в else ветка
  • исследовать возвращаемое значение accept отдельно
  • убедиться, что errno сбрасывается на 0 перед каждым из системных вызовов

В Linux, когда вы создаете соединение и оно закрывается, вам придется подождать некоторое время, прежде чем устанавливать новое соединение. Как и в Linux, сокет не освобождает порт no. как только вы закроете розетку.

ИЛИ ЖЕ

Вы повторно используете сокет, тогда плохой дескриптор файла хочет прийти.

Другие вопросы по тегам