Неправильное поведение MacOSX select () при неблокирующем соединении - PullRequest
1 голос
/ 09 августа 2009

Я играю со слоем сокетов в моей кроссплатформенной структуре и пытаюсь заставить соединения работать неблокирующим образом. Однако после того, как они пролили документы, они, похоже, вообще не ведут себя правильно. Суть проблемы заключается в том, что после инициирования неблокирующего соединения следующие избранные ошибки не позволяют обнаружить, что соединение успешно установлено и время ожидания снова и снова истекает.

SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
hostent *h = gethostbyname("www.memecode.com");
if (h)
{
    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);

    if (h->h_addr_list && h->h_addr_list[0])
    {
        memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(in_addr));

        // Set non blocking
        fcntl(s, F_SETFL, O_NONBLOCK);

        int64 start = LgiCurrentTime();
        int status = connect(s, (sockaddr*) &addr, sizeof(sockaddr_in));
        printf("Initial connect = %i\n", status);
        while (status && (LgiCurrentTime()-start) < 15000)
        {
            //  Do select to wait for connect to finish
            fd_set wr;
            FD_ZERO(&wr);
            FD_SET(s, &wr);
            int TimeoutMs = 1000;
            struct timeval t = {TimeoutMs / 1000, (TimeoutMs % 1000) * 1000};
            errno = 0;
            int64 sel_start = LgiCurrentTime();
            int ret = select(0, 0, &wr, 0, &t);
            int64 sel_end = LgiCurrentTime();
            printf("%i = select(0,%i,0) errno=%i time=%i\n",
                ret,
                FD_ISSET(s, &wr)!=0,
                errno,
                (int)(sel_end-sel_start));

            if (ret > 0 && FD_ISSET(s, &wr))
            {
                // ready for connect to finish...
                status = connect(s, (sockaddr*) &addr, sizeof(sockaddr_in));
                printf("2nd connect = %i\n", status);
                if (status)
                {
                    if (errno == EISCONN)
                    {
                        status = 0;
                        printf("error = EISCONN so we're good.\n");
                    }
                }
            }
            // else still waiting...
        }
    }
    else printf("host addr error.\n");
}
else printf("gethostbyname failed.\n");

Когда я запускаю этот код на последней сборке Leopard MacOSX, я получаю такой вывод:

Initial connect = -1
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1001
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000

Когда я удаляю условие «ret> 0» после выбора, следующее соединение успешно завершается и возвращает EISCONN. Таким образом, соединение работает за кулисами, но избранный никогда не подхватывает его. Насколько я понимаю, возвращаемое значение select содержит количество сокетов в структурах fd_set и возвращает 0, если ни у одного из них нет событий.

Что не так с моим кодом?

PS LgiCurrentTime () возвращает миллисекунды с некоторой точки, например, GetTickCount для Windows ... Я забыл точное значение для Mac, но это не важно ... просто информация о времени.

1 Ответ

1 голос
/ 09 августа 2009

Я считаю, что первый параметр select(..) должен быть самым большим номером дескриптора файла +1, а не 0, что делает его

int ret = select(s+1, 0, &wr, 0, &t);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...