1) Если речь идет об событиях, типа последовательных WSASend - то да. Только не понятно что значит пакет завершения. Если это означает выход потока порта из ожидания, то после двух send будет два выхода. В MS ISA Server, которая использует порты завершения, есть рекомендация, не выполнять более двух send операций без их завершения. А еще лучше выполнять одну и дожидаться появления в порте завершения. Связано с производительностью и сопротивлению атаке Denial of service.
...
if ( WSASend( ptag->ClientSocket, &ptag->SendBuf, 1, &dwCtrl,
dwFlags, (WSAOVERLAPPED*) &ptag->SendOverlapped, NULL) == 0)
{
//Вызов был синхронным.
}
// Ждем проявления в порте завершения
if (
(WaitForSingleObjectEx(ptag->SendComplete, NETCS_MAXWAIT_SEND, TRUE) == WAIT_OBJECT_0)
&&
(ptag->SendError == ERROR_SUCCESS)
)
{
// Дождались. Не ошибка
fRes = TRUE;
}
2) В случае ошибки при операции WSASend или WSARecv выход из потока все равно произойдет.
ThreadNotifyId TCPSRVAPI CTcpServer::IoPortLoop(CBaseThread* pThread)
{
...
fRes = GetQueuedCompletionStatus( FIoPort, &dwNumBytes,
(ULONG_PTR*) &ptag, &pOverlapped,
INFINITE);
if ( !fRes)
{
IoPortHandleError(ptag, pOverlapped); //Обработка ошибки
}
...
}
3) Вытекает из 2). Все зависит от типа ошибки. Разрыв соединения это не только выход по ошибке. Думаю ты знаешь, что значит принять 0 байт. Ну и, наверное, не каждая ошибка есть разрыв соединения. Допустим, сокет, привязанный к порту, в состоянии listen, и операция send завершилась неудачей (один из клиентов откинулся или таймаут), мы получаем FALSE на выходе из GetQueuedCompletionStatus. А как насчет других клиентов? Мы не перестанем получать выходы из потоков порта...
P.S.: Конечно лучше всего, это почитать Рихтера. Кстати,
у него, в операция WSASend и WSARecv на месте lpNumberOfBytesSent и lpNumberOfBytesRecvd частенько стоит NULL. НИКОГДА ТАК НЕ ДЕЛАЙ! Месяца два ловил глюки (W2K Server).
P.P.S: Недавно обсуждалась тема "Из сокета может прийти мусор?". Важно учесть ее в самом начале!