Предположим я уже подключился через одну из трёх функций и вот уже хочу отправить данные. Для этого я буду использовать WSASend():
int result=0;
char buffer[32];
// Заполняю буфер данными
WSABUF bufferSend;
bufferSend.buf=buffer;
bufferSend.len=32;
DWORD sendBytes=0;
MYOVERLAPPED overlapped; // Унаследованная от WSAOVERLAPPED
overlapped.type=TYPE_SEND;
result=WSASend(client,&bufferSend,1,&sendBytes,0,&overlapped,0);
// Проверка значения в result
Что же тут может произойти? Во-первых, может возникнуть ошибка (сеть недоступна) или штатная ситуация, когда соединение было завершено (например завершено удалённой стороной). Во-вторых, возможны ситуации, когда функция тут же передаст управление (я полагаю именно в данной ситуации sendBytes вернёт столько, сколько нам нужно было передать и ни на байт меньше, я прав?). В-третьих: если операция не может быть выполнена немедленно, то функция вернёт нам WSA_IO_PENDING. Да, оговорюсь, не функция вернёт, а код ошибки вернёт, при возвращении функцией значения SOCKET_ERROR. Но вот не понятно мне в каком случае может вернуться WSA_OPERATION_ABORTED. Мы же только запустили функцию, она должна мгновенно передать управление. Это что, если вдруг за это мгновение я из другого потока отменил перекрёстную (асинхронную) операцию, то вот это и произойдёт? Что-то мне кажется маловероятным возникновение такой ситуации. Или я ошибаюсь?
Но больше всего меня интересует следующее, если мы получили WSA_IO_PENDING, то значит ли это, что при ожидании завершения:
В numberBytes всегда будет такое значение, сколько мы хотели отправить? Просто в противном случае было бы больше кода отслеживания. Хотя я сам уже думаю что всё таки получить тут я могу разное число, но могу ли я получить тут 0 и в каких случаях?
Мне не понятно поведение системы в такой вот ситуации: я вызываю WSASend() и прошу её передать 75 МБ (размер выбрал для наглядности примера). Соединение с сокетом существует, операция не может быть выполнена мгновенно, в результате я получу ошибку WSA_IO_PENDING (собственно это успешная ошибка). Я занимаюсь своими делами, а система за меня отсылает данные (видимо тут я только должен позаботиться чтобы буфер с отсылаемыми данными не накрылся при выходе из области видимости, в которой вызывалась WSASend(), то есть сделать его не на стеке как в приведённом выше примере). Через 40 секунд сервер (а может и я сам) завершает соединение со мной, но я успел передать только 13 МБ. Функция GetQueuedCompletionStatus() передаст управление. И вопрос к Вам, что она мне вернёт?
Re: Есть вопрос по работе с сокетом через порты завершения в
Здравствуйте, s3dworld, Вы писали:
..... S>Мне не понятно поведение системы в такой вот ситуации: я вызываю WSASend() и прошу её передать 75 МБ (размер выбрал для наглядности примера). Соединение с сокетом существует, операция не может быть выполнена мгновенно, в результате я получу ошибку WSA_IO_PENDING (собственно это успешная ошибка). Я занимаюсь своими делами, а система за меня отсылает данные (видимо тут я только должен позаботиться чтобы буфер с отсылаемыми данными не накрылся при выходе из области видимости, в которой вызывалась WSASend(), то есть сделать его не на стеке как в приведённом выше примере). Через 40 секунд сервер (а может и я сам) завершает соединение со мной, но я успел передать только 13 МБ. Функция GetQueuedCompletionStatus() передаст управление. И вопрос к Вам, что она мне вернёт?
Скока передаст столько и вернет. Тоже относиться и к синхронному выполнению WSASend.
Re: Есть вопрос по работе с сокетом через порты завершения в
Здравствуйте, s3dworld, Вы писали:
S>Мне не понятно поведение системы в такой вот ситуации: я вызываю WSASend() и прошу её передать 75 МБ (размер выбрал для наглядности примера). Соединение с сокетом существует, операция не может быть выполнена мгновенно, в результате я получу ошибку WSA_IO_PENDING (собственно это успешная ошибка). Я занимаюсь своими делами, а система за меня отсылает данные (видимо тут я только должен позаботиться чтобы буфер с отсылаемыми данными не накрылся при выходе из области видимости, в которой вызывалась WSASend(), то есть сделать его не на стеке как в приведённом выше примере). Через 40 секунд сервер (а может и я сам) завершает соединение со мной, но я успел передать только 13 МБ. Функция GetQueuedCompletionStatus() передаст управление. И вопрос к Вам, что она мне вернёт?
В теории — что угодно (ошибку или число от 1 до 75M).
На практике — 75M если оно поместилось в буфер ядра (т.е. вызов завершился до того как стало известно о разрыве соединения), или ошибку.
Я как-то недавно экспериментировал с различными большими кусками данных, и ни разу не удалось получить иного результата.
Re[2]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, 11molniev, Вы писали:
1>Здравствуйте, s3dworld, Вы писали: 1>..... S>>Мне не понятно поведение системы в такой вот ситуации: я вызываю WSASend() и прошу её передать 75 МБ (размер выбрал для наглядности примера). Соединение с сокетом существует, операция не может быть выполнена мгновенно, в результате я получу ошибку WSA_IO_PENDING (собственно это успешная ошибка). Я занимаюсь своими делами, а система за меня отсылает данные (видимо тут я только должен позаботиться чтобы буфер с отсылаемыми данными не накрылся при выходе из области видимости, в которой вызывалась WSASend(), то есть сделать его не на стеке как в приведённом выше примере). Через 40 секунд сервер (а может и я сам) завершает соединение со мной, но я успел передать только 13 МБ. Функция GetQueuedCompletionStatus() передаст управление. И вопрос к Вам, что она мне вернёт?
1>Скока передаст столько и вернет. Тоже относиться и к синхронному выполнению WSASend.
То есть получается, что когда я хочу передать 7 МБ, на порт завершения может прийти уведомление,где в параметре lpNumberOfBytes я получу 3 МБ и мне нужно снова вызвать WSASend() чтобы отправить не отправленные 4 МБ (не подумайте что я буду отправлять заново весь буфер, только то, что не отправилось)? Вообще странное поведение для асинхронной функции. Я то думал что если я хочу отправить 7 МБ, то она хоть в лоб разобъётся, но в порт отправится пакет либо если все 7 МБ передаст, либо если произойдёт ошибка. А тот через задницу.
А если в момент асинхронной операции произойдёт отключение сокета, где я могу получить код ошибки после получения управления от GetQueuedCompletionStatus()? Просто вызвав GetLastError()?
Re[3]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, s3dworld, Вы писали:
S>То есть получается, что когда я хочу передать 7 МБ, на порт завершения может прийти уведомление,где в параметре lpNumberOfBytes я получу 3 МБ и мне нужно снова вызвать WSASend() чтобы отправить не отправленные 4 МБ (не подумайте что я буду отправлять заново весь буфер, только то, что не отправилось)?
На практике параметр lpNumberOfBytes возвратит либо 0, либо 7 МБ !!!
Другое означает сбой винды.
S>А если в момент асинхронной операции произойдёт отключение сокета, где я могу получить код ошибки после получения управления от GetQueuedCompletionStatus()? Просто вызвав GetLastError()?
Верно (если WSASend вернула WSA_IO_PENDING).
Re[4]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, acDev, Вы писали:
D>Здравствуйте, s3dworld, Вы писали:
S>>То есть получается, что когда я хочу передать 7 МБ, на порт завершения может прийти уведомление,где в параметре lpNumberOfBytes я получу 3 МБ и мне нужно снова вызвать WSASend() чтобы отправить не отправленные 4 МБ (не подумайте что я буду отправлять заново весь буфер, только то, что не отправилось)?
D>На практике параметр lpNumberOfBytes возвратит либо 0, либо 7 МБ !!! D>Другое означает сбой винды.
S>>А если в момент асинхронной операции произойдёт отключение сокета, где я могу получить код ошибки после получения управления от GetQueuedCompletionStatus()? Просто вызвав GetLastError()?
D>Верно (если WSASend вернула WSA_IO_PENDING).
Спасибо!
А у меня вот такой вопрос. Стоит ли создавать несколько портов завершения для обработки тысячи сокетов или же лучше всех их привязать к одному порту?
Re[5]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, s3dworld, Вы писали:
S>А у меня вот такой вопрос. Стоит ли создавать несколько портов завершения для обработки тысячи сокетов или же лучше всех их привязать к одному порту?
Не стоит, т.к. это только нагрузит ядро винды лишней работой.
Эта задача разруливается правильной организацией пула потоков IOCP и количеством потоков в пуле.
Re: Есть вопрос по работе с сокетом через порты завершения в
Здравствуйте, s3dworld, Вы писали:
S>Мне не понятно поведение системы в такой вот ситуации: я вызываю WSASend() и прошу её передать 75 МБ ... Функция GetQueuedCompletionStatus() передаст управление. И вопрос к Вам, что она мне вернёт?
Думаю, что в ответ на WSASend функция GetQueuedCompletionStatus() вернет либо 0 (в случае если операция не была выполнена до конца) либо 75Мб (в случае если операция была выполнена до конца). Никогда не сталкивался с тем, чтобы GetQueuedCompletionStatus() возвращала, например, "34 Мб переданы успешно, а остальные нет".
У меня "смежная" с темой проблема, помогите, пожалуйста разобраться.
Вызываю WSASend() и прошу передать 75Мб. Функция WSASend() возвращает результат 0, что означает, что операция выполнена, вызов GetQueuedCompletionStatus() также сообщает мне, что операция завершена и все данные отправлены полностью. В действительности данные еще никуда не передавались, а ОС просто скопировала их в свои внутренние буферы (уж не знаю куда) и только начала их передачу. Если теперь при передаче этих 75 Мб произойдет ошибка и данные не будут отправлены полностью, как я об этом узнаю?
Re[2]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, DenRaskatov, Вы писали:
DR>Вызываю WSASend() и прошу передать 75Мб. Функция WSASend() возвращает результат 0, что означает, что операция выполнена, вызов GetQueuedCompletionStatus() также сообщает мне, что операция завершена и все данные отправлены полностью. В действительности данные еще никуда не передавались, а ОС просто скопировала их в свои внутренние буферы (уж не знаю куда) и только начала их передачу.
При таком большом буфере вы не получите 0 от WSASend, вы получите SOCKET_ERROR. И будете вынуждены "ждать ошибки" на GetQueuedCompletionStatus().
Re[3]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, acDev, Вы писали:
D>При таком большом буфере вы не получите 0 от WSASend, вы получите SOCKET_ERROR. И будете вынуждены "ждать ошибки" на GetQueuedCompletionStatus().
Вы правы, действительно от WSASend() получаю SOCKET_ERROR. Однако, из GetQueuedCompletionStatus() возвращаюсь до того, как все данные переданы.
Возможно я что-то путаю: GetQueuedCompletionStatus() так и должна работать, сообщая, что данные именно отправлены, а не получены. С другой стороны, протокол TCP является надежным и на каждый переданный пакет получает подтверждение от принимающей стороны. Почему тогда функция GetQueuedCompletionStatus() не устроена так, чтобы я получал уведомление о завершении операции отправки, только когда все данные доставлены и подтверждены?
Может надо какую-то опцию на сокете установить?
Re[3]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, acDev, Вы писали:
D>При таком большом буфере вы не получите 0 от WSASend, вы получите SOCKET_ERROR. И будете вынуждены "ждать ошибки" на GetQueuedCompletionStatus().
Если опцию SO_SNDBUF установить равную 0, то от WSASend получаю SOCKET_ERROR.
Если опцию SO_SNDBUF установить не равной 0, то от WSASend получаю 0.
Re[4]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, DenRaskatov, Вы писали:
DR>Вы правы, действительно от WSASend() получаю SOCKET_ERROR. Однако, из GetQueuedCompletionStatus() возвращаюсь до того, как все данные переданы.
Вы даёте мало инфы. После SOCKET_ERROR (WSASend) напишите что возвращает WSAGetLastError(). Также напишите что возвращает GetQueuedCompletionStatus() и WSAGetLastError().
DR>Если опцию SO_SNDBUF установить равную 0, то от WSASend получаю SOCKET_ERROR. DR>Если опцию SO_SNDBUF установить не равной 0, то от WSASend получаю 0.
Опять таки судить только по SOCKET_ERROR не могу. Проверяйте WSAGetLastError().
И напишите буфер какого размера выставляете и сколько передаёте.
Re[5]: Есть вопрос по работе с сокетом через порты завершени
Возвращаюсь из GetQueuedCompletionStatus до того, как все данные доставлены принимающей стороне. Хотелось бы вернуться из GetQueuedCompletionStatus только после того, как все данные доставлены и подтверждены. Возможно ли это?
Если есть время и желание разобраться в нюансах IOCP, то рекомендую посмотреть исходники Boost.Asio.
Например, completion packet может приходить в GetQueuedCompletionStatus раньше, чем произойдет выход из соотв. WSASend/WSARecv. Мало кто об этом знает. И в MSDN кроме предложения использовать "какой-нибудь reference counting" ничто не намекает на эту особенность.
Programs must be written for people to read, and only incidentally for machines to execute
Re[6]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, DenRaskatov, Вы писали:
DR>Возвращаюсь из GetQueuedCompletionStatus до того, как все данные доставлены принимающей стороне. Хотелось бы вернуться из GetQueuedCompletionStatus только после того, как все данные доставлены и подтверждены. Возможно ли это? DR> wsaOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, "");
Так вы указываете Event. Вот поэтому то, видимо, у вас такой результат.
Да и вообще не понятно зачем вам IOCP, коли WSASend и GetQueuedCompletionStatus в одном потоке ...
Re[5]: Есть вопрос по работе с сокетом через порты завершени
Здравствуйте, acDev, Вы писали:
D>Так вы указываете Event. Вот поэтому то, видимо, у вас такой результат.
Не понял, что Вы хотели сказать . Как же иначе?
D>Да и вообще не понятно зачем вам IOCP, коли WSASend и GetQueuedCompletionStatus в одном потоке ...
Это только для простоты примера.
Re[6]: Есть вопрос по работе с сокетом через порты завершени
D>>Так вы указываете Event. Вот поэтому то, видимо, у вас такой результат. DR>Не понял, что Вы хотели сказать . Как же иначе?
Просто у меня чистый IOCP с пулом потоков.
А ты видимо хочешь событийный сервак написать или просто не понимаешь для чего в структуре WSAOVERLAPPED есть hEvent.
Re[7]: Есть вопрос по работе с сокетом через порты завершени