pBuffer = message + p->static_buf_len;
p->static_buf_len = 0;
while (nRemainRecv > 0 && !Disconnect) {
nXfer = recv(sd, TempBuf, nRemainRecv, 0);
if (nXfer <= 0) {
Disconnect = TRUE;
continue;
}
nRemainRecv –= nXfer;
/* Передать в целевое сообщение все символы вплоть до нулевого, если таковой имеется. */
for (k =0; k < nXfer && TempBuf[k] != '\0'; k++) {
*pBuffer = TempBuf[k];
pBuffer++;
}
if (k >= nXfer) { /*Признак конца строки не обнаружен, читать дальше*/
nRemainRecv –= nXfer;
} else { /* Обнаружен признак конца строки. */
*pBuffer = '\0';
nRemainRecv = 0;
memcpy(p->static_buf, &TempBuf[k + 1], nXfer – k – 1);
p->static_buf_len = nXfer – k – 1;
}
}
return Disconnect;
}
_declspec(dllexport)
BOOL SendCSMessage(RESPONSE *pResponse, SOCKET sd) {
/* Послать запрос серверу в сокет sd. */
BOOL Disconnect = FALSE;
LONG32 nRemainSend, nXfer;
LPSTR pBuffer;
pBuffer = pResponse->Record;
nRemainSend = strlen(pBuffer) + 1;
while (nRemainSend > 0 && !Disconnect) {
/* Отправка еще не гарантирует, что будет отослано все сообщение. */
nXfer = send(sd, pBuffer, nRemainSend, 0);
if (nXfer <= 0) {
fprintf(stderr, "\nОтключение сервера до посылки запроса завершения");
Disconnect = TRUE;
}
nRemainSend –=nXfer;
pBuffer += nXfer;
}
return Disconnect;
}
Комментарии по поводу DLL и безопасной многопоточной среды
• Всякий раз, когда создается новый поток, вызывается функция DllMain с опцией DLL_THREAD_ATTACH, но для основного потока отдельного вызова с опцией DLL_THREAD_ATTACH не существует. В случае основного потока должна использоваться опция DLL_PROCESS_ATTACH.
• Вообще говоря, в том числе и в данном случае (возьмите, например, поток, принимающий сообщения (accept thread)), некоторым потокам распределение памяти может и не требоваться, но DllMain не в состоянии различать отдельные типы потоков. Поэтому на участке кода, соответствующем варианту выбора DLL_THREAD_ATTACH, фактического распределения памяти не происходит; здесь только инициализируется параметр TLS. Распределение памяти осуществляется точкой входа ReceiveCSMessage при первом ее вызове. Благодаря этому собственная память выделяется только тем потокам, которые в этом действительно нуждаются, и различные типы потоков получают ровно столько ресурсов, сколько им требуется.
• Хотя рассматриваемая библиотека DLL и обеспечивает безопасную многопоточную поддержку, любой поток в каждый момент времени может работать только с одним сокетом, поскольку долговременные состояния ассоциируются не с сокетами, а с потоками. Этот момент учитывается в следующем примере.
• Исходным кодом DLL, размещенным на Web-сайте, предусмотрен вывод общего количества вызовов DllMain в соответствии с их типами.
• Даже при таком решении существует риск утечки ресурсов. Некоторые потоки, например поток приема сообщений, могут вообще не завершаться, и поэтому не будут отсоединены от библиотеки DLL. Для остающихся активных потоков функция ExitProcess вызовет DllMain с опцией DLL_PROCESS_DETACH, а не DLL_THREAD_DETACH. В данном случае никаких проблем не возникает, поскольку поток приема сообщений никаких ресурсов не распределяет, а освобождение памяти происходит по завершении процесса. Однако, проблемы возможны в тех случаях, когда потоки распределяют такие ресурсы, как временные файлы. Поэтому окончательное решение должно предусматривать создание глобально доступного списка ресурсов. Тогда участок кода, соответствующий опции DLL_PROCESS_DETACH, мог бы взять на себя просмотр этого списка и освобождение ненужных ресурсов.
Пример: альтернативная стратегия создания безопасных библиотек DLL с много поточной поддержкой