Socket select () блокирует второй раз - PullRequest
1 голос
/ 12 ноября 2011

У меня есть простая программа сервер / клиент, над которой я работаю. Я использую select(), чтобы дождаться поступления данных в сокет TCP, прежде чем читать их. Когда данные поступают, я использую несколько вызовов recv() и select() для чтения в чанках, пока у меня не получится все это , Затем я возвращаюсь к начальному вызову select() и проверяю, есть ли у клиента что-нибудь еще для отправки.

struct timeval timeoutCounter;
fd_set readFileDescriptor;
do {
    timeoutCounter.tv_sec = 30;
    timeoutCounter.tv_usec = 0;
    FD_ZERO(&readFileDescriptor);
    FD_SET(socket, &readFileDescriptor);
    cout << "This line always prints, every iteration through the loop.\n";
    dataReady = select(socket+1,&readFileDescriptor,NULL,NULL,&timeoutCounter);
    cout << "This line only prints the first time I call select()."
         << "The second time it hangs before reaching this line.\n";

    // ... recv(), select(), recv(), select(), etc in a loop until I have all the data
    // send() a response to the client
} while(dataReady > 0);

Я начал со всего этого в большой, трудной для чтения функции, и это сработало. Тогда я разбил его на отдельный класс от того, который accept() связывает, и теперь его поведение отличается. Первый набор данных, который отправляет пользователь, приходит в порядке. Но клиент ожидает ответа от сервера и затем отправляет второй набор данных в сокет. Однако select() не возвращается после того, как клиент отправит второй набор данных; блокируется до истечения времени ожидания.

Я уже исключил клиента как проблему; пакеты отправляются нормально и в соответствующее время. Я также попытался напечатать дескриптор файла сокета, чтобы доказать, что он где-то не меняется. У кого-нибудь есть идеи, почему этот код может не работать? Какие факторы могут вызвать блокировку select()?

РЕДАКТИРОВАТЬ: Похоже, мой код работает нормально на 32-разрядных компьютерах, но не работает на 64-разрядных компьютерах. Я до сих пор не решил проблему, но это немного сужает ее.

1 Ответ

3 голосов
/ 12 ноября 2011

Не видя вашего полного кода, трудно понять, что может быть не так. Однако функция select() изменяет значения fd_set, переданные ей. Вам необходимо убедиться, что вы повторно инициализируете каждое значение fd_set перед вызовом select(), чтобы включить нужные сокеты.

Помните также, что функция recv() будет блокироваться, пока не получит некоторые данные (или сокет не будет закрыт), поэтому, если вам действительно не нужна функция тайм-аута, вам, возможно, даже не понадобится вызывать select(). Наконец, функция recv() вернется, если доступны любые данные, необязательно все того, что вы просили. Вам придется многократно вызывать recv() в цикле, чтобы получить все данные. Это верно, даже если вы читаете небольшое количество байтов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...