Delphi winsock Почему значения sockaddr_in становятся "искаженными" при назначении InAddr.S_addr

Я нашел функцию, чтобы проверить, открыт ли какой-либо порт tcp на удаленном ПК. Кажется, что все работает нормально, но когда я присваиваю значение переменной client.sin_addr.S_addr, другим значениям присваиваются искаженные значения, ну, по крайней мере, я не ожидал увидеть такие значения, как то, что я вижу.

Значения записи клиента перед назначением client.sin_addr.S_addr:

(2, 39173, ((#0, #0, #0, #0), (0, 0), 0), (#0, #0, #0, #0, #0, #0, #0, #0), 2, (#5, '™', #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, #0))

Значения записи клиента после назначения client.sin_addr.S_addr:

(2, 39173, (('À', '¨', #10, 'h'), (43200, 26634), 1745529024), (#0, #0, #0, #0, #0, #0, #0, #0), 2, (#5, '™', 'À', '¨', #10, 'h', #0, #0, #0, #0, #0, #0, #0, #0))

Обратите внимание, что 1745529024 является правильным представлением IP-адреса 192.168.10.104.

Функция работает как ожидалось, насколько я могу видеть. Мне просто не нравятся эти искаженные значения.

Является ли это нормальным, я должен беспокоиться или просто игнорировать его?

function PortTCP_IsOpen(dwPort : Word; InetAddress : AnsiString) : boolean;
var
 client : sockaddr_in;
 sock : Integer;
 GInitData: TWSAData;
 ret : Integer;
 res : integer;
 msg : string;
begin
 Result:=False;
 ZeroMemory(@client, SizeOf(client));
 ret := WSAStartup($0002, GInitData); //initiates use of the Winsock DLL
 if ret <> 0 then RaiseLastOSError;
 try
 client.sin_family := AF_INET; //Set the protocol to use , in this case (IPv4)
 client.sin_port := htons(dwPort); //convert to TCP/IP network byte order (big-endian)
 // before value
 client.sin_addr.S_addr := inet_addr(PAnsiChar('192.168.10.104')); //inet_addr(PAnsiChar(ansistring(GetIPFromHost(InetAddress)))); //convert to IN_ADDR structure
 // after value
 sock := socket(AF_INET, SOCK_STREAM, 0); //creates a socket
 Result:= connect(sock, client, SizeOf(client)) = 0; //establishes a connection to a specified socket
 if Result then
 begin
 if not closesocket(sock) = 0 then
 begin
 res := WSAGetLastError;
 msg := SysErrorMessage(res);
 raise Exception.CreateFmt('%s Code:%d',[msg, res]);
 end;
 end else
 begin
 res := WSAGetLastError;
 msg := SysErrorMessage(res);
 raise Exception.CreateFmt('%s Code:%d',[msg, res]);
 end;
 finally
 WSACleanup;
 end;
end;
2 ответа

Это вариантная запись, подобная C-соединению. Вот он:

type
 in_addr = record
 case integer of
 0: (S_un_b: SunB);
 1: (S_un_w: SunW);
 2: (S_addr: u_long);
 end;

Итак, S_addr содержит значение 1745529024, а остальные два члена накладываются на одну и ту же память. В hex, 1745529024 есть $680AA8C0.

Теперь, что такое SunB?

type
 SunB = record
 s_b1, s_b2, s_b3, s_b4: u_char;
 end;

Таким образом, отладчик интерпретирует четыре байта S_addr как кодированные ANSI символы, следовательно, то, что вы видите в отладчике. Посмотрите $68, $0A, $A8 и $C0 в своей локальной таблице ANSI, и вы найдете четыре значения, которые показал вам отладчик.

Аналогично для SunW, который есть:

type
 SunW = record
 s_w1, s_w2: u_short;
 end;

И два слова, составляющие $680AA8C0, действительно $A8C0 = 43200 и $680A = 26634.

Таким образом, ситуация нормальная, о чем не о чем беспокоиться.


Эти поля объявляются как удерживающие значения Char, поэтому отладчик интерпретирует их таким образом и пытается отобразить символы. Конечно, они не являются персонажами, но отладчик не знает ничего лучше.

Десятичное значение 1745529024 является шестнадцатеричным 0x680AA8C0. Самым значимым байтом является 0x68, который при интерпретации символа ASCII имеет нижний регистр h. Значение 0x0A является строкой, представленной в виде символа символа Delphi как #10. И так далее.

licensed under cc by-sa 3.0 with attribution.