// для перекрытого чтения длины строки
procedure ReadLenCompleted(dwError: DWORD; cdTransferred: DWORD; lpOverlapped: PWSAOverlapped; dwFlags: DWORD); stdcall;
var
// Указатель на соединение
Connection: PConnection;
// Указатель на буфер
Buf: TWSABuf;
// Параметры для WSARecv
NumBytes, Flags: DWORD;
begin
// Для идентификации операции в функцию передается указатель
// на запись TWSAOverlapped. Ищем по этому указателю
// подходящее соединение в списке FConnections.
Connection:= ServerForm.GetConnectionByOverlapped(lpOverlapped);
if Connection = nil then
begin
ServerForm.AddMessageToLog(
'Внутренняя ошибка программы — не найдено соединение');
Exit;
end;
// Проверяем, что не было ошибки
if dwError <> 0 then
begin
ServerForm.AddMessageToLog('Клиент ' + Connection.ClientAddr +
' — ошибка при чтении длины строки: ' + GetErrorString(dwError));
ServerForm.RemoveConnection(Connection);
Exit;
end;
// Уменьшаем число оставшихся к чтению байтов
// на размер полученных данных
Dec(Connection.BytesLeft, cdTransferred);
if Connection.BytesLeft < 0 then
// Страховка от "тупой" ошибки
ServerForm.AddMessageToLog('Клиент ' + Connection.ClientAddr +
' — внутренняя ошибка программы: получено больше байтов, ' +
'чем ожидалось');
ServerForm.RemoveConnection(Connection);
end
else if Connection.BytesLeft = 0 then
begin
// Длина строки прочитана целиком
if Connection.MsgSize <= 0 then
begin
ServerForm.AddMessageToLog('Клиент ' + Connection.ClientAddr +
' — получена неверная длина строки ' +
IntToStr(Conneсtion.MsgSizе));
ServerForm.RemoveConnection(Connection);
Exit;
end;
// Делаем строку нужной длины
SetLength(Connection.Msg, Connection.MsgSize);
// Данные пока не прочитаны, поэтому смещение — ноль,
// осталось прочитать полную длину.
Connection.Offset:= 0;
Connection.BytesLeft:= Connection.MsgSize;
// Заносим размер буфера и указатель на него в Buf.
// Данные будут складываться в строку,
// на которую ссылается Connection.Msg.
Buf.Len:= Connection.MsgSize;
Buf.Buf:= Pointer(Connection.Msg);
// Вызываем WSARecv для чтения самой строки
Flags:= 0;
if WSARecv(Connect ion.ClientSocket, @Buf, 1, NumBytes, Flags,
@Connection.Overlapped, ReadMsgCompleted) = SOCKET_ERROR then
begin
if WSAGetLastError <> WSA_IO_PENDING then
begin
ServerForm.AddMessageToLog('Клиент ' + Connection.ClientAddr +
' — ошибка при чтении строки: ' + GetErrorString(dwError));
ServerForm.RemoveConnection(Connection);
end;
end;
end
else
begin
// Connection.BytesLeft < 0 — длина строки
// прочитана не до конца.
// Увеличиваем смещение на число прочитанных байтов