Ответ содержится в документации WinSock.
WSAConnectByNameW()
function
Когда функция WSAConnectByName
возвращает TRUE, сокет s
находится в состоянии по умолчанию для подключенного сокета. Сокет s
не разрешает ранее установленные свойства или параметры, пока для сокета не будет установлен SO_UPDATE_CONNECT_CONTEXT. Используйте функцию setsockopt , чтобы установить параметр SO_UPDATE_CONNECT_CONTEXT.
Итак, когда WSAConnectByNameW()
возвращает TRUE, getpeername()
завершается неудачно с WSAENOTCONN
, потому что вы не вызываете setsockopt(SO_UPDATE_CONNECT_CONTEXT)
, чтобы перевести сокет в надлежащее состояние. Это поясняется в документации SOL_SOCKET Socket Options :
SO_UPDATE_CONNECT_CONTEXT
Эта опция используется с ConnectEx
, WSAConnectByList
, и WSAConnectByName
функций. Эта опция обновляет свойства сокета после установления соединения. Эта опция должна быть установлена, если на подключенном разъеме должны использоваться функции getpeername
, getsockname
, getsockopt
, setsockopt
или shutdown
.
Попробуйте это:
bRes := WSAConnectByNameW(hSocket, PChar(nodeName), PChar(serviceName),
{var}localAddressLength, {var}localAddress,
{var}remoteAddressLength, {var}remoteAddress,
nil, nil);
if not bRes then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
// ADD THIS..
errorCode := setsockopt(hSocket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, nil, 0);
if errorCode <> 0 then
begin
errorCode := WSAGetLastError;
RaiseLastOSError(errorCode);
end;
...
При этом нет необходимости использовать getpeername()
в вашем примере, потому что он возвращает ту же информацию, которую WSAConnectByNameW()
уже возвращает в переменной, которую вы передаете его RemoteAddress
параметр.