Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2013.03.22;
Скачать: CL | DM;

Вниз

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;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.052 c
15-1340051402
Юрий
2012-06-19 00:30
2013.03.22
С днем рождения ! 19 июня 2012 вторник


15-1342299109
Дмитрий С
2012-07-15 00:51
2013.03.22
Сохранить/Восстановить содержимое CMOS биоса.


2-1336248923
rodionov-uv
2012-05-06 00:15
2013.03.22
Документ Word и Delphi


15-1352384190
Artem
2012-11-08 18:16
2013.03.22
Можно ли сменить размер виртуального диска в VirtualBox?


15-1340687560
AV
2012-06-26 09:12
2013.03.22
Что то пропустил, как так можно делать?