【问题标题】:VBA Winsock Not Working with Longer Port Length (sin_port)VBA Winsock 不适用于更长的端口长度 (sin_port)
【发布时间】:2017-04-04 14:30:57
【问题描述】:

我创建了下面的 Excel VBA 代码,它使用 Winsock API 连接到 IP 地址,从 Excel 单元格发送文本字符串并接收文本字符串作为回报。

我的代码最初指向 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

【问题讨论】:

  • 您无法更改这些结构中的类型。这些结构的全部意义在于它们是一个定义良好的二进制接口。将其改回整数。
  • 你的 htons 也是错误的。它适用于 16 位类型。缺少无符号类型对您来说很不方便。您将需要更好地掌握二进制表示、字节序、二进制补码等。
  • @MajorCoder 您在哪里找到要添加到项目的参考?我在我的项目 PC(W7-64 位)上的任何地方都找不到它。

标签: vba excel sockets winapi winsock


【解决方案1】:

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

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

您遇到的真正问题是VBA 的Integer 类型是有符号,它可以容纳的最高值是32767。如果您尝试使用更高的值,它将转为负数.

Winsock 的实际sockaddr_in 结构(和htons() 函数)对sin_port 字段使用16 位无符号 类型。 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")。

【讨论】:

    猜你喜欢
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    • 2015-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多