Привет,
в процессе написания класса сетевого клиента, столкнулся со следующей проблемой:
Я создаю сокет (pSocket = new...), вызываю async_connect(). Completion callback connect'а возвращает no error.
Вызываю асинхронное async_read_some() и, не дожидаясь, пока сработает callback read'а, закрываю сокет (пробовал по-разному — вызов socket.shutdown(shutdown_both), вызов socket.close()), затем уничтожаю объект сокета (delete pSocket);
После чего создаю сокет опять, и вызываю async_connect(). Completion callback в этот раз возвращает ошибку 995: The I/O operation has been aborted because of either a thread exit or an application request
ну, понятно, что я отменил I/O operation, но ведь я закрыл сокет и создал совсем другой. Почему я получаю нотификацию об ошибке при открытии нового соединения?
Что-то подсказывает, что это особенность работы Windows IO Completion Ports (я в них не разбирался — мне дай бог с asio разобраться ), и эти Completion Ports привязываются к потоку, а не к сокету, но вроде ж так не должно себя вести.
В чем может быть проблема? И как правильно тогда сделать?
Спасибо!
Здравствуйте, savitar, Вы писали:
S>колбэк с ошибкой вызвается для закрытого сокета, а не для вновь созданного. это легко проверить не создавая нового сокета и не вызывая async_connect.
Но почему вызывается connect_handler()? В документации сказано,
cancel() causes all outstanding asynchronous connect, send and receive operations to finish immediately, and the handlers for cancelled operations will be passed the asio::error::operation_aborted error.
connect_handler() при первом коннекте солбщил 0 (нет ошибки) — то есть операция async_connect() завершась для этого сокета, она уже не должна вызываться с asio::error::connection_abort при разрушении сокета повторно. Разве нет?
Еще в документации нашел момент годе говорится
Remarks
Calls to cancel() will always fail with asio::error::operation_not_supported when run on Windows XP, Windows Server 2003, and earlier versions of Windows, unless ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has two issues that should be considered before enabling its use:
It will only cancel asynchronous operations that were initiated in the current thread.
It can appear to complete without error, but the request to cancel the unfinished operations may be silently ignored by the operating system. Whether it works or not seems to depend on the drivers that are installed.
For portable cancellation, consider using one of the following alternatives:
Disable asio's I/O completion port backend by defining ASIO_DISABLE_IOCP.
Use the close() function to simultaneously cancel the outstanding operations and close the socket.
When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above.
У меня как раз WinXP, приложение состоит из одного потока, никаких дополнительных дефайнов (навроде ASIO_DISABLE_IOCP) я не указывал.
Или я что-то не так понял?
не путай close() и cancel(), если ты не вызываешь cancel(), то соответственно нет необходимости объявлять BOOST_ASIO_ENABLE_CANCELIO.
Так у тебя обработчик коннекта ошибку выдает, я изначально подумал что чтения.
Приведи минимальный код воспроизводящий проблему.
Спасибо за ответ
S>не путай close() и cancel(), если ты не вызываешь cancel(), то соответственно нет необходимости объявлять BOOST_ASIO_ENABLE_CANCELIO.
А разве cancel() не вызывается автоматически, когда соединение разрывается, когда объект сокет деаллоцируется или когда я вызываю shutdown()? Не нашел внятного объяснения этого механизма в Asio Reference
Вообще, имеет смысл отменять все незавершенные операции (используя cancel()), когда я удаляю сокет (например, когда получил от сервера сообщение о том, что соединение можно разорвать)?
Здравствуйте, Michaels1, Вы писали:
M>А разве cancel() не вызывается автоматически, когда соединение разрывается, когда объект сокет деаллоцируется или когда я вызываю shutdown()?
Нет. M>Вообще, имеет смысл отменять все незавершенные операции (используя cancel()), когда я удаляю сокет (например, когда получил от сервера сообщение о том, что соединение можно разорвать)?
Все сделает close().
Здравствуйте, savitar, Вы писали:
S>Здравствуйте, Michaels1, Вы писали:
M>>А разве cancel() не вызывается автоматически, когда соединение разрывается, когда объект сокет деаллоцируется или когда я вызываю shutdown()? S>Нет. M>>Вообще, имеет смысл отменять все незавершенные операции (используя cancel()), когда я удаляю сокет (например, когда получил от сервера сообщение о том, что соединение можно разорвать)? S>Все сделает close().
понятно, спасибо
(тот callback вызывался из-за неправильной работы с указателями)