Асинхронные сокеты (Windows 7)

Тема в разделе "WASM.NETWORKS", создана пользователем AlwaysAlone, 7 июл 2011.

  1. AlwaysAlone

    AlwaysAlone New Member

    Публикаций:
    0
    Регистрация:
    19 июн 2011
    Сообщения:
    20
    Здравствуйте
    Пишу небольшое серверное приложение, которое обслуживает несколько клиентов, с помощью WSASelect() и очереди сообщений главного GUI окна.

    Проблема в том, что я никак не могу поймать FD_CLOSE.
    Клиент — консольное приложение, которое подключается к серверу, обменивается какими-то данными и, после нажатия любой клавиши в консольном окне, завершается (тем самым разрывая соединение).

    Я "вовермя" получаю FD_ACCEPT и FD_READ, но FD_CLOSE приходит только после того, как клиент уже завершился и я его запустил вновь — т.е. после повторного соединения.

    Почему это может происходить?
    Разве завершение процесса — это не graceful disconnect?
    Клиентская система — unix (MacOS).

    Код (Text):
    1.  SOCKET clientsAcceptingSocket = socket(PF_INET, SOCK_STREAM, 0);
    2.     SOCKADDR_IN clientsAcceptingSockAddr;
    3.     clientsAcceptingSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    4.     clientsAcceptingSockAddr.sin_port = htons(SERVER_ACCEPTS_CLIENTS_ON_PORT);
    5.     clientsAcceptingSockAddr.sin_family = AF_INET;
    6.     if(bind(clientsAcceptingSocket, (SOCKADDR*)&clientsAcceptingSockAddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
    7.         //...
    8.         exit(1);
    9.     }
    10.  
    11.     listen(clientsAcceptingSocket, 0);
    12.     if(WSAAsyncSelect(clientsAcceptingSocket,h_wnd,WM_SOCKET_CLIENT_TCP_EVENT, FD_ACCEPT|FD_READ|FD_CLOSE)) {
    13.         //...
    14.         exit(1);
    15.     }
    В "message pump" я, при встрече сообщения WM_SOCKET_CLIENT_TCP_EVENT, вызываю эту функцию:
    Код (Text):
    1. void TCPSocketEvent(UINT uMsg, WPARAM wParam, LPARAM lParam) {
    2. if(WSAGETSELECTEVENT(lParam) & FD_ACCEPT) { //incoming connection
    3.     cout <<  "FD_ACCEPT\n";
    4.     SOCKET acceptedSocket = accept(wParam, (struct sockaddr*)&acceptedSockAddr, &acceptedSockAddrLen);
    5.     if(acceptedSocket!=INVALID_SOCKET) {
    6.         //tcp connection successfully accepted
    7.     }
    8. }
    9. if(WSAGETSELECTEVENT(lParam) & FD_CLOSE) {
    10.     cout <<  "FD_CLOSE\n";
    11. }
    12. if(WSAGETSELECTEVENT(lParam) & FD_READ) {
    13.     cout <<  "FD_READ\n";
    14.     //здесь я читаю данные, и, возможно, отсылаю данные с помощью send()
    15. }
    Подскажите, что я не так делаю?
    Спасибо
     
  2. dinoweb

    dinoweb Дмитрий

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    129
    Адрес:
    Россия. Красноярск
    Нужно явно закрывать соединение клиентом, иначе он не отправит сообщение о разрыве соединения серверу. В таком случае соединение будет висеть, пока не случится таймаут.
     
  3. AlwaysAlone

    AlwaysAlone New Member

    Публикаций:
    0
    Регистрация:
    19 июн 2011
    Сообщения:
    20
    dinoweb
    Спасибо
    А не подскажете, какие существует способы на сервере определить что приложение-клиент "упало"?
     
  4. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Когда приложение падает, оно перестаёт отвечать на запросы, для этого и есть таймаут. Очевидно.
     
  5. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    AlwaysAlone

    Если вместе с клиентом не взорвался комп, то для TCP это будет "An existing connection was forcibly closed by the remote host".
     
  6. AlwaysAlone

    AlwaysAlone New Member

    Публикаций:
    0
    Регистрация:
    19 июн 2011
    Сообщения:
    20
    _DEN_
    Ezrah
    dinoweb

    Когда приложение-клиент падает, оно посылает RST вместо обмена тройным FIN - ACK+FIN - ACK.
    Как в Windows обработать эту ситуацию? Наипростейший способ - через WSAAsyncSelect - к сожалению не работает. FD_CLOSE приходит только для FIN-дисконнекта.
    Во многих системах (Mac/BSD/Linux) "приходит" нечто вроде FD_READ с 0 в качестве к-ва прочитанных байт, но только не в Windows.

    Как бы вы сделали?
     
  7. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    AlwaysAlone

    Зачем тебе этот онанизм на голом апи? Возьми Boost.Asio - на нем твоя задача решается за 5 минут и без лишнего мусора.
     
  8. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    Нет тут никакого мусора, на голом апи тоже все просто.

    AlwaysAlone, у вас ошибка в том, что вы забыли сделать WSAAsyncSelect для сокета передачи данных, acceptedSocket. FD_CLOSE приходит именно для него - ведь именно сокет передачи данных закрывается при закрытии TCP-соединения, а не clientsAcceptingSocket.
     
  9. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Dmitry_Milk
    Прежде чем давать такие комментарии, следует посмотреть что такое Boost.Asio.
     
  10. AlwaysAlone

    AlwaysAlone New Member

    Публикаций:
    0
    Регистрация:
    19 июн 2011
    Сообщения:
    20
    Всем спасибо за помощь
    Я не получал RST из-за того что приложение из-за своей специфики включало файрвол (divert TCP-траффика) и не выключало его по завершению, из-за чего TCP пакеты просто убивались. Я совершенно забыл и удивлялся почему же оно не работает, написал кучу тестов для разных систем и наконец-то удалось локализовать проблему.
    Извините за беспокойство :)

    Dmitry_Milk
    В msdn сказано что
    так что это наверное лишнее..

    _DEN_
    asio хорошая библиотека, вот только тянет она за собой целый boost. Для простенького низкоуровневого приложения для "принять 2 байта" мне хватает и встроенных средств OC :)

    Спасибо за советы
     
  11. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    AlwaysAlone
    Ага, а C++ - хороший язык, вот только тянет за собой весь STL.
     
  12. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Всё это гумно. .net рулит. ^)
     
  13. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    Booster
    net самая тупая хрень которая может быть.
     
  14. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    984259h
    Где аргументы?
     
  15. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    да да, факты в студию!