VBA Winsock 无法使用更长的端口长度 (sin_port)

VBA Winsock Not Working with Longer Port Length (sin_port)

我创建了以下 Excel VBA 代码,它使用 Winsock API 连接到 IP 地址,从 Excel 发送文本字符串单元格并在 return.

中接收文本字符串

我的代码最初指向 IP 地址 127.0.0.1 和端口 80,没有任何问题。但是,我不得不将目标端口更新为 60401,这还需要将端口输入变量 sin_port 更改为 Long,因为新端口超过了 VBA 整数的最大长度.在这些更新之后,代码仍然可以编译,但是 Winsock API 不处理任何东西??

我认为错误可能与 sin_zero 变量有关,随着端口长度的增加,该变量可能缓冲了太多的零?我试过调整这个变量并诊断其他地方的代码,但在修改代码几个小时后它仍然没有处理。

非常感谢所有帮助。谢谢。


原始代码 - 端口 80 - 成功编译和处理

Type WSAData
   wVersion As Integer
   wHighVersion As Integer
   szDescription(0 To 255) As Byte
   szSystemStatus(0 To 128) As Byte
   iMaxSockets As Integer
   iMaxUdpDg As Integer
   lpVendorInfo As Long
End Type

Type sockaddr_in
    sin_family As Integer
    sin_port As Integer
    sin_addr As Long
    sin_zero(0 to 7) As Byte
End Type

Public Declare Function WSAStartup Lib "ws2_32" ( _
    ByVal wVersionRequired As Integer, ByRef lpWSAData As WSAData) As Long

Public Declare Function WSAGetLastError Lib "ws2_32" () As Long

Public Declare Function socket Lib "ws2_32" ( _
    ByVal af As Long, ByVal socktype As Long, ByVal protocol As Long) As Long

Public Declare Function connect Lib "ws2_32" ( _
    ByVal sock As Long, ByRef name As sockaddr_in, ByVal namelen As Integer) As Long

Public Declare Function send Lib "ws2_32" ( _
    ByVal sock As Long, ByVal buf As String, ByVal bufLen As Long, ByVal flags As Long) As Long

Public Declare Function recv Lib "ws2_32" ( _
    ByVal sock As Long, ByRef buf As Byte, ByVal bufLen As Long, ByVal flags As Long) As Long

Public Declare Function inet_addr Lib "ws2_32" ( _
    ByVal s As String) As Long

Public Declare Function htons Lib "ws2_32" ( _
    ByVal hostshort As Long) As Long


Function FetchData() As String
   Dim iReturn As Long
   Dim wsaDat As WSAData
   iReturn = WSAStartup(&H202, wsaDat)

   If iReturn <> 0 Then
      MsgBox "WSAStartup failed", 0, ""

   End If

   Dim sock As Long
   Dim sock1 As Long
   Dim lasterr As Long
   Dim i As Long
   Dim buf(10) As Byte
   Dim s As String
   Dim j As Integer

   sock = socket(2, 1, 6)

   Dim addr As sockaddr_in
   addr.sin_family = 2
   addr.sin_port = htons(80)
   addr.sin_addr = inet_addr("127.0.0.1")

   i = connect(sock, addr, LenB(addr))
   i = send(sock, "*SRTF" & vbCr, 6, 0)
   i = recv(sock, buf(0), 10, 0)

   For j = 0 To i - 1
     s = s & Chr(buf(j))
   Next
   FetchData = s
End Function

Sub Button2_Click()
    Range("C3").Formula = FetchData()
End Sub

新代码 - 端口 60401 - 编译,但不处理?

Type WSAData
   wVersion As Integer
   wHighVersion As Integer
   szDescription(0 To 255) As Byte
   szSystemStatus(0 To 128) As Byte
   iMaxSockets As Integer
   iMaxUdpDg As Integer
   lpVendorInfo As Long
End Type

Type sockaddr_in
    sin_family As Integer
    sin_port As Long
    sin_addr As Long
    sin_zero(0 to 7) As Byte
End Type

Public Declare Function WSAStartup Lib "ws2_32" ( _
    ByVal wVersionRequired As Integer, ByRef lpWSAData As WSAData) As Long

Public Declare Function WSAGetLastError Lib "ws2_32" () As Long

Public Declare Function socket Lib "ws2_32" ( _
    ByVal af As Long, ByVal socktype As Long, ByVal protocol As Long) As Long

Public Declare Function connect Lib "ws2_32" ( _
    ByVal sock As Long, ByRef name As sockaddr_in, ByVal namelen As Integer) As Long

Public Declare Function send Lib "ws2_32" ( _
    ByVal sock As Long, ByVal buf As String, ByVal bufLen As Long, ByVal flags As Long) As Long

Public Declare Function recv Lib "ws2_32" ( _
    ByVal sock As Long, ByRef buf As Byte, ByVal bufLen As Long, ByVal flags As Long) As Long

Public Declare Function inet_addr Lib "ws2_32" ( _
    ByVal s As String) As Long

Public Declare Function htons Lib "ws2_32" ( _
    ByVal hostshort As Long) As Long


Function FetchData() As String
   Dim iReturn As Long
   Dim wsaDat As WSAData
   iReturn = WSAStartup(&H202, wsaDat)

   If iReturn <> 0 Then
      MsgBox "WSAStartup failed", 0, ""

   End If

   Dim sock As Long
   Dim sock1 As Long
   Dim lasterr As Long
   Dim i As Long
   Dim buf(10) As Byte
   Dim s As String
   Dim j As Integer

   sock = socket(2, 1, 6)

   Dim addr As sockaddr_in
   addr.sin_family = 2
   addr.sin_port = htons(60401)
   addr.sin_addr = inet_addr("127.0.01")

   i = connect(sock, addr, LenB(addr))
   i = send(sock, "*SRTF" & vbCr, 6, 0)
   i = recv(sock, buf(0), 10, 0)

   For j = 0 To i - 1
     s = s & Chr(buf(j))
   Next
   FetchData = s
End Function

Sub Button2_Click()
    Range("C3").Formula = FetchData()
End Sub

您更改了 sockaddr_in 的定义,以便为 sin_port 字段使用更大的数据类型。你不能那样做。您需要恢复原始定义以保持与 Winsock 兼容。

你对htons()的定义也是错误的。 ws2_32 中真正的 htons() 函数作用于 16 位数字,而不是您定义的 32 位数字(htonl() 作用于 32 位数字)。

你 运行 遇到的真正问题是 VBA 的 Integer 类型是 signed,它可以容纳的最大值是 32767。如果您尝试使用更高的值,它将换行为负值。

Winsock 的实际 sockaddr_in 结构(和 htons() 函数)对 sin_port 字段使用 16 位 unsigned 类型。 VBA 根本没有 16 位 unsigned 类型。所以你必须忍受 16 位 signed Integer.

的限制

您需要修正您的定义:

Type sockaddr_in
  sin_family As Integer
  sin_port As Integer
  sin_addr As Long
  sin_zero(0 to 7) As Byte
End Type

Public Declare Function htons Lib "ws2_32" ( _ ByVal hostshort As Integer) As Integer

现在,话虽这么说,无符号 数字 60401 是十六进制 0xEBF1。这与 signed 数字 -5135 的值相同。当 htons().

交换字节时变为 0xF1EB (-3605)

所以,请尝试以下方法之一:

addr.sin_port = htons(&HEBF1)

addr.sin_port = htons(-5135)

addr.sin_port = -3605

此外,inet_addr("127.0.01") 应该读作 inet_addr("127.0.0.1")