WinSock closesocket/socket/connect

Тема в разделе "WASM.NETWORKS", создана пользователем PE_Kill, 29 ноя 2008.

  1. PE_Kill

    PE_Kill New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2006
    Сообщения:
    107
    Подскажите по винсоку.

    Делаю

    Код (Text):
    1.       // Sleep(1000) ; <- смотрите ниже
    2.  
    3.       //==========================================================================
    4.       // Открываем сокет
    5.       //==========================================================================
    6.       Sock:=Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    7.       if Sock = SOCKET_ERROR then Exit;      
    8.       //==========================================================================
    9.       // CloseSocket будет закрывать сокет грубо и ждать пока не закроется
    10.       //==========================================================================
    11.       Linger.l_onoff := 1;
    12.       Linger.l_linger:= 0;
    13.       if setsockopt(Sock, SOL_SOCKET, SO_LINGER, @Linger, sizeof(Linger))<>0 then
    14.       begin
    15.         closesocket(Sock);
    16.         Exit;
    17.       end;
    18.       //==========================================================================
    19.       // Разблокируем сокет
    20.       //==========================================================================
    21.       Block:=1;
    22.       if ioctlsocket(Sock,FIONBIO,Block)<>0 then
    23.       begin
    24.         _closesocket(Sock);
    25.         Exit;
    26.       end;
    27.       //==========================================================================
    28.       // Коннектимся к хосту
    29.       //==========================================================================
    30.       AddrIn.sin_addr.s_addr :=inet_addr(sHost);
    31.       AddrIn.sin_family :=AF_INET;
    32.       AddrIn.sin_port :=htons(aPorts[iPort]);
    33.       connect(Sock,AddrIn,sizeof(AddrIn));
    34.       if WSAGetLastError <> WSAEWouldBlock then
    35.       begin
    36.         _closesocket(Sock);
    37.         Continue;
    38.       end;
    39.       //==========================================================================
    40.       // Блокируем сокет
    41.       //==========================================================================
    42.       Block:=0;
    43.       if ioctlsocket(Sock,FIONBIO,Block)<>0 then
    44.       begin
    45.         _closesocket(Sock);
    46.         Exit;
    47.       end;      
    48.       //==========================================================================
    49.       // Ждем коннекта по таймауту 10 сек
    50.       //==========================================================================
    51.       FD_Zero(SetW);
    52.       FD_Set(Sock,SetW);
    53.       FD_Zero(SetE);
    54.       FD_Set(Sock,SetE);
    55.       timeval.tv_sec := 10;
    56.       timeval.tv_usec:= 00;
    57.       TimeOut := select(0,nil,@SetW,@SetE,@timeval);
    Всё работает как надо, но только в двух случаях. Либо этот код прогоняется 1 раз, либо для этого кода создается отдельный тред. У меня этот код в цикле. Первый раз цикл отрабатывает нормально, а все последующие итерации connect возвращает TimeOut = 0. Я уже и shutdown делал, и после shutdown селект пытался юзать и SO_LINGER коментил и после closesocket снова вызывал select. Всё равно все последующие итерации connect не работает.

    Помогло только одно, перед началом следующей итерации ставлю Sleep(1000), вот тогда всё нормально, все итерации конекты проходят нормально. Мне не понятно в чем дело, я ведь выставил SO_LINGER чтобы сокет сразу же закрывался, да и какая разница вообще, ведь если даже сокет занят, то функция socket должна вернуть свободный, но вот без Sleep оно почему то не работает. Я конечно могу оставить и так, но это как то не по дзенски, должны жить быть какие то легальные методы. Переколупал разные сорсы, везде, где есть подобный код - вижу Sleep в пределах 1000 (обычно чуть меньше), сталобыть я не первый такой.
     
  2. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    PE_Kill, ты хочешь асинхронный connect()? Это просто так не сделать. Есть два варианта:
    a) отдельный поток и у него очередь (ессно он делает blocking connect())

    b) IO completion ports - в Server 2003 и Vista есть ConnectEx - overlapped версия
     
  3. PE_Kill

    PE_Kill New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2006
    Сообщения:
    107
    s0larian я не хочу асинхронный коннект. Я хочу коннект по таймауту. Для этого я разблокирую сокет вызываю асинхронно коннект и селектом жду пока не выйдет время либо пока не приконектимся, потом снова блокируем сокет ну дальше уже не интересно. Код приведенный выше прекрасно работает, либо коннектится либо отваливается по таймауту, но это только первый раз, после закрытия сокета и создания нового следующий connect всегда отваливается по таймауту. Работает только если после закрытия сокета вызвать Sleep(1000) и потом только снова всё прогонять. Вот и интересует почему так.

    Т.е. например тот код выше исполняется в отдельном потоке в цикле, отрабатывает без Sleep(1000) один раз а потом всегда connect валится в таймаут.
     
  4. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    Эта, у тебя тут ошибки, кажется:
    1) в вызове socket() надо иметь IPPROTO_TCP
    2) socket поставь в blocking mode перед вызовом closesocket()
    3) поставь SO_DONTLINGER
    4) tv_sec в секундах
    5) в select() нужно послать кол-во sockets
     
  5. PE_Kill

    PE_Kill New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2006
    Сообщения:
    107
    Поставил IPPROTO_TCP действительно итерации стали проходить медленнее. И, о чудо, на второй итерации connect тоже прошел удачно! Но дальше всё повторилось, причем чем выше итерация тем быстрее пролетает connect, на 1000ной итерации connect занимает милисекунды а потом вообще вылетает программа.

    Поставил сразу после connect ничего не изменилось

    Оно и так по умолчанию стоит я мне надо чтобы closesocket ждал пока сокет окончательно не закроется, а вообще проверял и так и так ниче не меняется.

    У меня и так в секундах

    Это где такой параметр? Структуры передаваемые и так содержат количество сокетов, первый параметр просто заглушка.
     
  6. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    что-то у тебя косячит... дельфизмы? :)

    Вот твой пример на С++ - всё пашет:
    Код (Text):
    1. namespace
    2. {
    3.     bool Connect(SOCKET sock, const std::string &host, uint16 port)
    4.     {
    5.         addrinfo aiHints, *aiList = NULL;
    6.  
    7.         memset(&aiHints, 0, sizeof(aiHints));
    8.         aiHints.ai_family = AF_INET;
    9.         aiHints.ai_socktype = SOCK_STREAM;
    10.         aiHints.ai_protocol = IPPROTO_TCP;
    11.  
    12.         // If the call succeeds, the aiList variable will hold a linked list
    13.         // of addrinfo structures containing response information about the host
    14.         if (getaddrinfo(host.c_str(), base::sprintfT<char>("%d", port).c_str(), &aiHints,
    15.             &aiList) != 0)
    16.             return false;
    17.  
    18.         if (connect(sock, aiList->ai_addr, sizeof(*aiList->ai_addr)) != SOCKET_ERROR)
    19.             return false;
    20.  
    21.         return GetLastError() == WSAEWOULDBLOCK;
    22.     }
    23.  
    24.     int32 Wait(SOCKET sock, uint32 seconds)
    25.     {
    26.         fd_set  set;
    27.         FD_ZERO(&set);
    28.         FD_SET(sock, &set);
    29.  
    30.         timeval timeout = { 4, 0 };
    31.  
    32.         return select(1, NULL, &set, NULL, &timeout);
    33.     }
    34.  
    35.     int UserMain(int argc, char *argv[])
    36.     {
    37.         base::Socket::InitializeWinsock();
    38.  
    39.         uint32  timeout = 0,
    40.                 connected = 0,
    41.                 error = 0;
    42.         for (uint32 i = 0; i < 1000; ++i)
    43.         {
    44.             // Create a non-clocking socket
    45.             SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    46.             if (sock == INVALID_SOCKET)
    47.                 return 1;
    48.             ULONG option = 1;
    49.             if (ioctlsocket(sock, FIONBIO, &option) != 0)
    50.                 return 1;
    51.  
    52.             // Initiate a connection
    53.             if (!Connect(sock, "localhost", 80))
    54.                 return 1;
    55.  
    56.             // Wait
    57.             int32 res = Wait(sock, 4);
    58.             switch (res)
    59.             {
    60.             case 0:
    61.                 timeout++;
    62.                 break;
    63.  
    64.             case 1:
    65.                 connected++;
    66.                 break;
    67.  
    68.             default:
    69.                 error++;
    70.             }
    71.  
    72.             option = 0;
    73.             if (ioctlsocket(sock, FIONBIO, &option) != 0)
    74.                 return 1;
    75.             closesocket(sock);
    76.         }
    77.  
    78.         std::cout << "Done: connected=" << connected << ", timeout=" << timeout
    79.                   << ", error=" << error << std::endl;
    80.         return 0;
    81.     }
    82. }
    83.  
    84. int main(int argc, char *argv[])
    85. {
    86.     int rv = UserMain(argc, argv);
    87.  
    88. #ifdef _DEBUG
    89.     _CrtMemDumpAllObjectsSince(NULL);
    90. #endif
    91.  
    92.     return rv;
    93. }
     
  7. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    Ну что, нашёл где косяк?