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

标签 vba excel sockets winapi winsock

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

我的代码最初指向带有端口127.0.0.1的IP地址80,没有任何问题。但是,此后我不得不将目标端口更新为60401,这还需要将端口输入变量sin_port更改为Long,因为新端口超过了VBA Integer的最大长度。在这些更新之后,代码仍然可以编译,但是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()的定义也是错误的。 htons()中的实际ws2_32函数对16位数字进行操作,而不是您定义的32位数字(htonl()对32位数字进行操作)。

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

Winsock的实际sockaddr_in结构(和htons()函数)对sin_port字段使用16位无符号类型。 VBA根本没有16位无符号类型。因此,您必须忍受16位带符号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是hex 0xEBF1。该值与带符号的-5135相同。当字节被0xF1EB交换时,它变成htons()(-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")

关于vba - VBA Winsock无法使用更长的端口长度(sin_port),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43197814/

相关文章:

vba - 将字符串值内的下划线字符替换为空格

c# - C#中的Excel互操作中的HRESULT代码

excel - 从 Excel 中的单元格中获取是、否或什么都没有

javascript - nodejs socket.io mysql 在套接字引用上缺少错误处理程序

python - 如何将 cv2.frames 发送到浏览器

c# - Winforms 服务器套接字应用程序

VBA 从文本文件的属性中获取日期

vba - 如何用 VBA 语法(不是 Excel 公式)编写数组公式

excel - Office 2016 中的 MailItem.GetInspector.WordEditor 生成应用程序定义或对象定义的错误

excel - VB新手。我的代码生成错误 : "expecting End With". with-end with 语句如何工作?