Delphi winsock 为什么在分配 InAddr.S_addr 时 sockaddr_in 值得到 "garbled"

Delphi winsock why does sockaddr_in values get "garbled" when assigning InAddr.S_addr

我找到了一个函数来测试远程 PC 上的特定 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([=16=]02, 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;

这些字段被声明为持有 Char 值,因此调试器以这种方式解释它们并尝试显示字符。当然,它们并不是真正的字符,但调试器并不知道更好。

十进制值1745529024十六进制为0x680AA8C0。最高有效字节是 0x68,当解释为 ASCII 字符时,它是小写 h。值 0x0A 是换行符,表示为 Delphi 字符文字 #10。等等。

这是一个变体记录,就像一个 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,另外两个成员覆盖在同一个内存上。在十六进制中,17455290240AA8C0.

现在,SunB 是什么?

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

因此调试器将 S_addr 的四个字节解释为 ANSI 编码字符,因此您在调试器中看到的是。在本地 ANSI table 中查找 </code>、<code>[=20=]A$A8$C0,您将找到调试器显示给您的四个值。

同样 SunW 即:

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

而组成0AA8C0的两个词确实是$A8C0 = 432000A = 26634

综上所述,情况正常,不用担心。