Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Вниз

DisconnectEx - как использовать?   Найти похожие ветки 

 
ProgRAMmer Dimonych ©   (2012-08-02 12:20) [0]

Программа многократно обращается по TCP к одним и тем же узлам сети: соединились, отправили блок запрос, получили ответ, закрыли соединение. Поставлена задача: не пересоздавать сокет при каждом обращении, а использовать один и тот же. Для этих целей, если верить гуглу и MSDN, предназначена DisconnectEx().

Попытка задействовать DisconnectEx() показала, что вместе с ней обычный connect() не прокатит и надо использовать ConnectEx(). Произведя замену, получаю код ошибки 10022 - WSAEINVAL, что в случае с ConnectEx() означает, что сокет не привязан. Делаю bind() на INADDR_ANY с нулевым портом - получаю при попытке чтения/записи из/в сокет 10057, 10048 или 10038.

Может ли кто-нибудь поделиться отсутствующим в MSDN примером правильного использования ConnectEx() и DisconnectEx() в связке? Или хотя бы рассказать о подводных камнях?

int CWSMonitor::ConnectWithTimeout(SOCKET s, WSAEVENT hConnectEvent, SOCKADDR *name, int namelen, DWORD Timeout)
{
int Result = 0;

while (TRUE)
{
 OVERLAPPED Overlapped;
 ZeroMemory(&Overlapped, sizeof(Overlapped));
 Overlapped.hEvent = hConnectEvent;
 ResetEvent(hConnectEvent);
 SOCKADDR_STORAGE sa_temp;
 ZeroMemory(&sa_temp, sizeof(sa_temp));
 sa_temp.ss_family = name->sa_family;
 switch (name->sa_family)
 {
 case AF_INET:
  ((LPSOCKADDR_IN)&sa_temp)->sin_addr.S_un.S_addr = INADDR_ANY;
  break;
 case AF_INET6:
  ((LPSOCKADDR_IN6)&sa_temp)->sin6_addr = in6addr_any;
  break;
 }
 bind(s, (LPSOCKADDR)&sa_temp, sizeof(sa_temp));
 if (FALSE == ConnectEx(s, name, namelen, NULL, 0, NULL, &Overlapped))
 {
  Result = WSAGetLastError();
  if (WSA_IO_PENDING != Result)
   break;
 }
 setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);

 DWORD dwTransfer, dwFlags;
 if (FALSE == WSAGetOverlappedResult(s, &Overlapped, &dwTransfer, TRUE, &dwFlags))
 {
  Result = WSAGetLastError();
  break;
 }

 Result = ERR_GOODRET;
 break;
}

return Result;
}


 
Rouse_ ©   (2012-08-02 19:53) [1]

TIME_WAIT учитываешь в 240 секунд перед повторным использованием?


 
ProgRAMmer Dimonych ©   (2012-08-02 20:44) [2]

> [1] Rouse_ ©   (02.08.12 19:53)
> TIME_WAIT учитываешь в 240 секунд перед повторным использованием?

М-м-м, да, на тестовом уже увидел. У меня, правда, в реестре на 30 секунд прописано, но дело, похоже, именно в нём. Пришлось отказаться от глупой затеи: запросы идут действительно очень часто.


 
Rouse_ ©   (2012-08-02 20:53) [3]

Затея действительно странная, я просто не вижу выигрыша от того что сокет не будет пересоздаваться. Только усложнение кода программы.


 
ProgRAMmer Dimonych ©   (2012-08-02 21:00) [4]

> [3] Rouse_ ©   (02.08.12 20:53)

Вышестоящие особы хотели сэкономить время на создании сокета. Не на подключении :)


 
Rouse_ ©   (2012-08-02 21:03) [5]


> ProgRAMmer Dimonych ©   (02.08.12 21:00) [4]
> > [3] Rouse_ ©   (02.08.12 20:53)
>
> Вышестоящие особы хотели сэкономить время на создании сокета.
>  Не на подключении :)

Да ну брось, он у тебя час чтоль создается? :)
Ты наоборот по времени проиграл, т.к. исполнение этого кода (даже если бы он работал) более продолжительное, чем время затрачиваемое на создание сокета :)


 
ProgRAMmer Dimonych ©   (2012-08-02 21:04) [6]

Вообще, кстати, интересный вопрос тогда: а смысл в DisconnectEx()? Ладно если бы, как они пишут в MSDN:

The interval of time that must elapse before TCP can release a closed connection and reuse its resources is known as the TIME_WAIT state or the 2MSL state. During this time, the connection can be reopened at much less cost to the client and server than establishing a new connection.

... и можно было соединиться "at much less cost". А так?


 
ProgRAMmer Dimonych ©   (2012-08-02 21:05) [7]

> [5] Rouse_ ©   (02.08.12 21:03)

Лично меня намного больше беспокоила скорость завершения потоков, которые эти запросы шлют: если соединение медленное, там бывало до десятка секунд требовалось.


 
ProgRAMmer Dimonych ©   (2012-08-02 21:06) [8]

P.S. Но это к теме не имеет никакого отношения


 
Rouse_ ©   (2012-08-02 21:06) [9]

Смысл в том что повторное соединение с теми-же параметрами (тот-же адрес и порт) происходит гораздо меньшими усилиями, т.к. в данный момент соединение реально еще не разорвано...


 
ProgRAMmer Dimonych ©   (2012-08-02 21:09) [10]

> [9] Rouse_ ©   (02.08.12 21:06)
> Смысл в том что повторное соединение с теми-же параметрами
> (тот-же адрес и порт) происходит гораздо меньшими усилиями,
> т.к. в данный момент соединение реально еще не разорвано...

Но ведь 240 секунд же до следующего успешного подключения. Или я туплю и речь идёт о том, чтобы привязать клиентский сокет к конкретным локальному адресу и порту?


 
Rouse_ ©   (2012-08-02 21:11) [11]


> Но ведь 240 секунд же до следующего успешного подключения

Нет, это в случае реюза, т.е. сначала стукнулся например на 127,0,0,1 а потом захотел на 192,168,0,10 - то сиди и жди. А если обратно на локалхост то сразу получишь на руки валидный описатель.


 
ProgRAMmer Dimonych ©   (2012-08-02 21:24) [12]

> [11] Rouse_ ©   (02.08.12 21:11)
>
> > Но ведь 240 секунд же до следующего успешного подключения
>
> Нет, это в случае реюза, т.е. сначала стукнулся например
> на 127,0,0,1 а потом захотел на 192,168,0,10 - то сиди и
> жди. А если обратно на локалхост то сразу получишь на руки
> валидный описатель.

Но у меня именно такая ситуация и была: и в проекте, и в тестовом приложении. На локалхост, на один и тот же порт. Может быть, я всё-таки чего-нибудь недокрутил с опциями сокета, например?


 
Rouse_ ©   (2012-08-02 21:29) [13]

Тут целиком проект смотреть нужно, по приведенному куску кода сложно сказать.
Накидай минимальную демку клиента и сервера, там и "будем посмотреть" :)


 
Rouse_ ©   (2012-08-02 21:33) [14]

Зы, ну и причеши код, раз уж на сях пишешь, а то:

if (FALSE == ConnectEx

if (FALSE == WSAGetOverlappedResult

 Result = WSAGetLastError();
 break;


 
ProgRAMmer Dimonych ©   (2012-08-02 21:41) [15]

> [13] Rouse_ ©   (02.08.12 21:29)

Вот моё тестовое для клиента: http://pastebin.com/YNKehGJM

Сервером у меня было приложение, которое висит на том же компе и слушает TCP-порт 5556.

Логика работы сервера: прочитать из сокета запрос, отправить ответ и сразу закрыть сокет. Тестовое приложение ничего не отправляет, так что сервер вряд ли...

Хотя стоп! Я правильно понимаю: сервер тоже не должен вызывать closesocket()? А с другой стороны closesocket() ведь максимум хэндл ему освободит.

В общем, тестовое у меня выдает 10022 и/или 10048, пока не сделаю интервал побольше.


 
ProgRAMmer Dimonych ©   (2012-08-02 21:43) [16]

> [14] Rouse_ ©   (02.08.12 21:33)

Причёсывание большого смысла не имеет: всё равно заставят обратно под общий стиль проекта чесать. Если бы на Delphi - там я ещё сам себе хозяин с большего.


 
Rouse_ ©   (2012-08-02 21:54) [17]


> ProgRAMmer Dimonych ©   (02.08.12 21:41) [15]

Ок, завтра с работы гляну как завал разгребу... ближе ко второй половине дня.


> всё равно заставят обратно под общий стиль проекта чесать.

Не понял, данные функции возвращают BOOL и работать с ними нужно как с BOOL, т.е. if (!ConnectEx и т.п. ну и return обычно используется не на выходе из функции а по факту. Нафига тянуть результат к концу функции, когда выйти можно уже сейчас с указанием результата?


 
Rouse_ ©   (2012-08-02 21:55) [18]

зы, ну это я уж не говорю про избыточное while (TRUE) :)


 
ProgRAMmer Dimonych ©   (2012-08-02 22:03) [19]

> [17] Rouse_ ©   (02.08.12 21:54)
> Не понял, данные функции возвращают BOOL и работать с ними
> нужно как с BOOL, т.е. if (!ConnectEx и т.п.

Здесь аргументация типа "А вдруг тип возвращаемого значения изменится? А APIшные - за компанию. И вообще: BOOL и bool - это разные типы". Отчасти правы, конечно, да и возбухать лишний раз не хоцца.

> ну и return
> обычно используется не на выходе из функции а по факту.
> Нафига тянуть результат к концу функции, когда выйти можно
> уже сейчас с указанием результата?

> зы, ну это я уж не говорю про избыточное while (TRUE) :)

Это вот такой модный способ не делать goto и не использовать исключения при обработке ошибок. Код защитный, а у них в былые времена исключения под защитой криво работали. Груз истории :)


 
Rouse_ ©   (2012-08-02 22:07) [20]


> и не использовать исключения при обработке ошибок

Ааа, понятно, да вирталочки не любят обработку исключений :)



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.077 c
2-1340260017
StudyMySQL
2012-06-21 10:26
2013.03.22
Вопрос по MySQL


15-1338799914
Empleado
2012-06-04 12:51
2013.03.22
iOS - security guide


15-1347371239
DevilDevil
2012-09-11 17:47
2013.03.22
Если тебе интересен Lua в Delphi


2-1335502666
leklerk
2012-04-27 08:57
2013.03.22
Когда нужно использовать CoInitialize?


15-1346949003
Опять я
2012-09-06 20:30
2013.03.22
Вопрос по Яндекс-почте.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский