Winsock send() 函数返回 -1 但 WSAGetLastError() 为 0Excel VBA 宏

问题描述

我正在编写一个 Excel 宏,以从联网的气象站检索一些数据并将其插入到电子表格中。气象站使用 TCP 进行通信。我用 *SRTF 发送一个数据包,它返回一个包含几个 ASCII 字符拼写温度的数据包,例如70.00

我的代码主要基于以下示例:https://www.keysight.com/main/editorial.jspx?ckey=1000001131:epsg:sud&id=1000001131:epsg:sud&nid=-11143.0.00&lc=eng&cc=US

正如问题标题所说,当我调用 send() 函数时,它返回 -1,表示出现错误。但是,如果我在之后立即调用 WSAGetLastError(),它会返回 0。有没有更好的方法解决这个问题?我不知道如何判断出了什么问题。它似乎可以正确连接和断开连接,所以我认为它不是防火墙或任何杀死它的东西...

ThisWorkbook 模块:

Private Sub get_hostname()
    
    Sheets("Sheet1").Select
    
    Range("B1").Select
    Hostname$ = ActiveCell.FormulaR1C1
    
End Sub

Sub GetWeatherData()
    Dim x As Long
    Dim recvBuf As String * 1024
    
    Call StartIt
    Call get_hostname
    x = OpenSocket(Hostname$,2000) ' port 2000
    
    ' read info here
    x = SendCommand("*SRTF") ' hm,this doesn't work,sends "-1" bytes but reports no other errors...
    x = RecvAscii(recvBuf,1024)
    Range("B2").Select
    ActiveCell.FormulaR1C1 = recvBuf
    
    Call CloseConnection
    Call EndIt
End Sub

FRAMEWRK 模块:

Public Const COMMAND_ERROR = -1
Public Const RECV_ERROR = -1
Public Const NO_ERROR = 0

Public socketId As Long

'Global Variables for WINSOCK
Global State As Integer

Sub CloseConnection()

    x = closesocket(socketId)
    
    If x = SOCKET_ERROR Then
        MsgBox ("ERROR: closesocket = " + Str$(x))
        Exit Sub
    End If

End Sub

Sub EndIt()

    'Shutdown Winsock DLL
    x = WSACleanup()

End Sub

Sub StartIt()

    Dim StartUpInfo As WSAData
    
    'Version 1.1 (1*256 + 1) = 257
    'version 2.0 (2*256 + 0) = 512
    
    'Get WinSock version
    version = 257
    
    'Initialize Winsock DLL
    x = WSAStartup(version,StartUpInfo)

End Sub
 
Function OpenSocket(ByVal Hostname As String,ByVal PortNumber As Integer) As Integer
   
    Dim I_SocketAddress As sockaddr_in
    Dim ipAddress As Long
    
    ipAddress = inet_addr(Hostname)

    'Create a new socket
    socketId = socket(AF_INET,SOCK_STREAM,0)
    If socketId = SOCKET_ERROR Then
        MsgBox ("ERROR: socket = " + Str$(socketId))
        OpenSocket = COMMAND_ERROR
        Exit Function
    End If

    'Open a connection to a server

    I_SocketAddress.sin_family = AF_INET
    I_SocketAddress.sin_port = htons(PortNumber)
    I_SocketAddress.sin_addr = ipAddress
    I_SocketAddress.sin_zero = String$(8,0)

    x = connect(socketId,I_SocketAddress,Len(I_SocketAddress))
    If socketId = SOCKET_ERROR Then
        MsgBox ("ERROR: connect = " + Str$(x))
        OpenSocket = COMMAND_ERROR
        Exit Function
    End If

    OpenSocket = socketId

End Function

Function SendCommand(ByVal command As String) As Integer

    Dim strSend As String
    
    strSend = command & vbCr
    
    Debug.Print ("Pre-send error: " & WSAGetLastError())
    count = send(socketId,ByVal strSend,Len(strSend),0)
    Debug.Print ("Post-send error: " & WSAGetLastError())
    Debug.Print (count)
        
    If count = SOCKET_ERROR Then
        'Debug.Print (WSAGetLastError())
        MsgBox ("ERROR: send = " + Str$(count))
        SendCommand = COMMAND_ERROR
        Exit Function
    End If
    
    SendCommand = NO_ERROR

End Function

Function RecvAscii(dataBuf As String,ByVal maxLength As Integer) As Integer

    Dim c As String * 1
    Dim length As Integer
    
    dataBuf = ""
    While length < maxLength
        DoEvents
        count = recv(socketId,c,1,0)
        If count < 1 Then
            RecvAscii = RECV_ERROR
            dataBuf = Chr$(0)
            Exit Function
        End If
        
        If c = Chr$(10) Then
           dataBuf = dataBuf + Chr$(0)
           RecvAscii = NO_ERROR
           Exit Function
        End If
        
        length = length + count
        dataBuf = dataBuf + c
    Wend
    
    RecvAscii = RECV_ERROR
    
End Function

WINSOCK 模块:

'This is the Winsock API deFinition file for Visual Basic

'Setup the variable type 'hostent' for the WSAStartup command
Type Hostent
  h_name As Long
  h_aliases As Long
  h_addrtype As String * 2
  h_length As String * 2
  h_addr_list As Long
End Type
Public Const SZHOSTENT = 16


'Set the Internet address type to a long integer (32-bit)
Type in_addr
   s_addr As Long
End Type


'A note to those familiar with the C header file for Winsock
'Visual Basic does not permit a user-defined variable type
'to be used as a return structure.  In the case of the
'variable deFinition below,sin_addr must
'be declared as a long integer rather than the user-defined
'variable type of in_addr.
Type sockaddr_in
   sin_family As Integer
   sin_port As Integer
   sin_addr As Long
   sin_zero As String * 8
End Type

Public Const WSADESCRIPTION_LEN = 256
Public Const WSASYS_STATUS_LEN = 128
Public Const WSA_DescriptionSize = WSADESCRIPTION_LEN + 1
Public Const WSA_SysstatusSize = WSASYS_STATUS_LEN + 1

'Setup the structure for the information returned from
'the WSAStartup() function.
Type WSAData
   wVersion As Integer
   wHighVersion As Integer
   szDescription As String * WSA_DescriptionSize
   szSystemStatus As String * WSA_SysstatusSize
   iMaxSockets As Integer
   iMaxUdpDg As Integer
   lpvendorInfo As String * 200
End Type

'Define socket return codes
Public Const INVALID_SOCKET = &HFFFF
Public Const SOCKET_ERROR = -1

'Define socket types
Public Const SOCK_STREAM = 1           'Stream socket
Public Const SOCK_DGRAM = 2            'Datagram socket
Public Const SOCK_RAW = 3              'Raw data socket
Public Const SOCK_RDM = 4              'Reliable Delivery socket
Public Const SOCK_SEQPACKET = 5        'Sequenced Packet socket


'Define address families
Public Const AF_UNSPEC = 0             'unspecified
Public Const AF_UNIX = 1               'local to host (pipes,portals)
Public Const AF_INET = 2               'internetwork: UDP,TCP,etc.
Public Const AF_IMPLINK = 3            'arpanet imp addresses
Public Const AF_PUP = 4                'pup protocols: e.g. BSP
Public Const AF_CHAOS = 5              'mit CHAOS protocols
Public Const AF_NS = 6                 'XEROX NS protocols
Public Const AF_ISO = 7                'ISO protocols
Public Const AF_OSI = AF_ISO           'OSI is ISO
Public Const AF_ECMA = 8               'european computer manufacturers
Public Const AF_DATAKIT = 9            'datakit protocols
Public Const AF_CCITT = 10             'CCITT protocols,X.25 etc
Public Const AF_SNA = 11               'IBM SNA
Public Const AF_DECnet = 12            'DECnet
Public Const AF_DLI = 13               'Direct data link interface
Public Const AF_LAT = 14               'LAT
Public Const AF_HYLINK = 15            'NSC Hyperchannel
Public Const AF_APPLETALK = 16         'AppleTalk
Public Const AF_NETBIOS = 17           'NetBios-style addresses
Public Const AF_MAX = 18               'Maximum # of address families


'Setup sockaddr data type to store Internet addresses
Type sockaddr
  sa_family As Integer
  sa_data As String * 14
End Type
Public Const SADDRLEN = 16


'Declare Socket functions

Public Declare Function closesocket Lib "wsock32.dll" (ByVal s As Long) As Long

Public Declare Function connect Lib "wsock32.dll" (ByVal s As Long,addr As sockaddr_in,ByVal namelen As Long) As Long

Public Declare Function htons Lib "wsock32.dll" (ByVal hostshort As Long) As Integer

Public Declare Function inet_addr Lib "wsock32.dll" (ByVal cp As String) As Long

Public Declare Function recv Lib "wsock32.dll" (ByVal s As Long,ByVal buf As Any,ByVal buflen As Long,ByVal flags As Long) As Long

Public Declare Function recvB Lib "wsock32.dll" Alias "recv" (ByVal s As Long,buf As Any,ByVal flags As Long) As Long

Public Declare Function send Lib "wsock32.dll" (ByVal s As Long,ByVal flags As Long) As Long

Public Declare Function socket Lib "wsock32.dll" (ByVal af As Long,ByVal socktype As Long,ByVal protocol As Long) As Long

Public Declare Function WSAStartup Lib "wsock32.dll" (ByVal wVersionrequired As Long,lpWSAData As WSAData) As Long

Public Declare Function WSACleanup Lib "wsock32.dll" () As Long

Public Declare Function WSAGetLastError Lib "wsock32.dll" () As Long

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)