📄 csocketmaster.cls
字号:
Private Function GetLocalHostName() As String
Dim strHostNameBuf As String * LOCAL_HOST_BUFF
Dim lngResult As Long
lngResult = api_gethostname(strHostNameBuf, LOCAL_HOST_BUFF)
If lngResult = SOCKET_ERROR Then
GetLocalHostName = vbNullString
Dim lngErrorCode As Long
lngErrorCode = Err.LastDllError
Err.Raise lngErrorCode, "CSocketMaster.GetLocalHostName", GetErrorDescription(lngErrorCode)
Else
GetLocalHostName = Left(strHostNameBuf, InStr(1, strHostNameBuf, Chr(0)) - 1)
End If
End Function
Private Function GetLocalIP() As String
Dim lngResult As Long
Dim lngPtrToIP As Long
Dim strLocalHost As String
Dim arrIpAddress(1 To 4) As Byte
Dim Count As Integer
Dim udtHostent As HOSTENT
Dim strIpAddress As String
strLocalHost = GetLocalHostName
lngResult = api_gethostbyname(strLocalHost)
If lngResult = 0 Then
GetLocalIP = vbNullString
Dim lngErrorCode As Long
lngErrorCode = Err.LastDllError
Err.Raise lngErrorCode, "CSocketMaster.GetLocalIP", GetErrorDescription(lngErrorCode)
Else
api_CopyMemory udtHostent, ByVal lngResult, LenB(udtHostent)
api_CopyMemory lngPtrToIP, ByVal udtHostent.hAddrList, 4
api_CopyMemory arrIpAddress(1), ByVal lngPtrToIP, 4
For Count = 1 To 4
strIpAddress = strIpAddress & arrIpAddress(Count) & "."
Next
strIpAddress = Left$(strIpAddress, Len(strIpAddress) - 1)
GetLocalIP = strIpAddress
End If
End Function
'If Host is an IP doesn't resolve anything and returns a
'a 32 bits long IP.
'If Host isn't an IP then returns vbNull, tries to resolve it
'in asynchronous way and acts according to enmDestination.
Private Function ResolveIfHostname(ByVal Host As String, ByVal enmDestination As DestResolucion) As Long
Dim lngAddress As Long
lngAddress = api_inet_addr(Host)
If lngAddress = INADDR_NONE Then 'if Host isn't an IP
ResolveIfHostname = vbNull
m_enmState = sckResolvingHost: If ShowDebug Then Debug.Print "STATE: sckResolvingHost"
If AllocateMemory Then
Dim lngAsynHandle As Long
lngAsynHandle = modSocketMaster.ResolveHost(Host, m_lngMemoryPointer, ObjPtr(Me))
If lngAsynHandle = 0 Then
FreeMemory
m_enmState = sckError: If ShowDebug Then Debug.Print "STATE: sckError"
Dim lngErrorCode As Long
lngErrorCode = Err.LastDllError
Dim blnCancelDisplay As Boolean
blnCancelDisplay = True
RaiseEvent Error(lngErrorCode, GetErrorDescription(lngErrorCode), 0, "CSocketMaster.ResolveIfHostname", "", 0, blnCancelDisplay)
If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.ResolveIfHostname"
Else
m_colWaitingResolutions.Add enmDestination, "R" & lngAsynHandle
If ShowDebug Then Debug.Print "Resolving host " & Host; " with handle " & lngAsynHandle
End If
Else
m_enmState = sckError: If ShowDebug Then Debug.Print "STATE: sckError"
If ShowDebug Then Debug.Print "Error trying to allocate memory"
Err.Raise sckOutOfMemory, "CSocketMaster.ResolveIfHostname", "Out of memory"
End If
Else 'if Host is an IP doen't need to resolve anything
ResolveIfHostname = lngAddress
End If
End Function
'Resolves a hots (if necessary) in synchronous way
'If succeeds returns a 32 bits long IP,
'strHostIP = readable IP string and lngErrorCode = 0
'If fails returns vbNull,
'strHostIP = vbNullString and lngErrorCode <> 0
Private Function ResolveIfHostnameSync(ByVal Host As String, ByRef strHostIP As String, ByRef lngErrorCode As Long) As Long
Dim lngPtrToHOSTENT As Long
Dim udtHostent As HOSTENT
Dim lngAddress As Long
Dim lngPtrToIP As Long
Dim arrIpAddress(1 To 4) As Byte
Dim Count As Integer
If Host = vbNullString Then
strHostIP = vbNullString
lngErrorCode = WSAEAFNOSUPPORT
ResolveIfHostnameSync = vbNull
Exit Function
End If
lngAddress = api_inet_addr(Host)
If lngAddress = INADDR_NONE Then 'if Host isn't an IP
lngPtrToHOSTENT = api_gethostbyname(Host)
If lngPtrToHOSTENT = 0 Then
lngErrorCode = Err.LastDllError
strHostIP = vbNullString
ResolveIfHostnameSync = vbNull
Else
api_CopyMemory udtHostent, ByVal lngPtrToHOSTENT, LenB(udtHostent)
api_CopyMemory lngPtrToIP, ByVal udtHostent.hAddrList, 4
api_CopyMemory arrIpAddress(1), ByVal lngPtrToIP, 4
api_CopyMemory lngAddress, ByVal lngPtrToIP, 4
For Count = 1 To 4
strHostIP = strHostIP & arrIpAddress(Count) & "."
Next
strHostIP = Left$(strHostIP, Len(strHostIP) - 1)
lngErrorCode = 0
ResolveIfHostnameSync = lngAddress
End If
Else 'if Host is an IP doen't need to resolve anything
lngErrorCode = 0
strHostIP = Host
ResolveIfHostnameSync = lngAddress
End If
End Function
'Returns local port from a connected or bound socket.
'Returns SOCKET_ERROR if fails.
Private Function GetLocalPort(ByVal lngSocket As Long) As Long
Dim udtSockAddr As sockaddr_in
Dim lngResult As Long
lngResult = api_getsockname(lngSocket, udtSockAddr, LenB(udtSockAddr))
If lngResult = SOCKET_ERROR Then
GetLocalPort = SOCKET_ERROR
Else
GetLocalPort = modSocketMaster.IntegerToUnsigned(api_ntohs(udtSockAddr.sin_port))
End If
End Function
Public Sub SendData(data As Variant)
Dim arrData() As Byte 'We store the data here before send it
If m_enmProtocol = sckTCPProtocol Then
If m_enmState <> sckConnected Then
Err.Raise sckBadState, "CSocketMaster.SendData", "Wrong protocol or connection state for the requested transaction or request"
Exit Sub
End If
Else 'If we use UDP we create a socket if there isn't one yet
If Not SocketExists Then Exit Sub
If Not BindInternal Then Exit Sub
m_enmState = sckOpen: If ShowDebug Then Debug.Print "STATE: sckOpen"
End If
'We need to convert data variant into a byte array
Select Case varType(data)
Case vbString
Dim strdata As String
strdata = CStr(data)
If Len(strdata) = 0 Then Exit Sub
ReDim arrData(Len(strdata) - 1)
arrData() = StrConv(strdata, vbFromUnicode)
Case vbArray + vbByte
Dim strArray As String
strArray = StrConv(data, vbUnicode)
If Len(strArray) = 0 Then Exit Sub
arrData() = StrConv(strArray, vbFromUnicode)
Case vbBoolean
Dim blnData As Boolean
blnData = CBool(data)
ReDim arrData(LenB(blnData) - 1)
api_CopyMemory arrData(0), blnData, LenB(blnData)
Case vbByte
Dim bytData As Byte
bytData = CByte(data)
ReDim arrData(LenB(bytData) - 1)
api_CopyMemory arrData(0), bytData, LenB(bytData)
Case vbCurrency
Dim curData As Currency
curData = CCur(data)
ReDim arrData(LenB(curData) - 1)
api_CopyMemory arrData(0), curData, LenB(curData)
Case vbDate
Dim datData As Date
datData = CDate(data)
ReDim arrData(LenB(datData) - 1)
api_CopyMemory arrData(0), datData, LenB(datData)
Case vbDouble
Dim dblData As Double
dblData = CDbl(data)
ReDim arrData(LenB(dblData) - 1)
api_CopyMemory arrData(0), dblData, LenB(dblData)
Case vbInteger
Dim intData As Integer
intData = CInt(data)
ReDim arrData(LenB(intData) - 1)
api_CopyMemory arrData(0), intData, LenB(intData)
Case vbLong
Dim lngData As Long
lngData = CLng(data)
ReDim arrData(LenB(lngData) - 1)
api_CopyMemory arrData(0), lngData, LenB(lngData)
Case vbSingle
Dim sngData As Single
sngData = CSng(data)
ReDim arrData(LenB(sngData) - 1)
api_CopyMemory arrData(0), sngData, LenB(sngData)
Case Else
Err.Raise sckUnsupported, "CSocketMaster.SendData", "Unsupported variant type."
End Select
'if there's already something in the buffer that means we are
'already sending data, so we put the new data in the buffer
'and exit silently
If Len(m_strSendBuffer) > 0 Then
m_strSendBuffer = m_strSendBuffer + StrConv(arrData(), vbUnicode)
Exit Sub
Else
m_strSendBuffer = m_strSendBuffer + StrConv(arrData(), vbUnicode)
End If
'send the data
SendBufferedData
End Sub
'Check which protocol we are using to decide which
'function should handle the data sending.
Private Sub SendBufferedData()
If m_enmProtocol = sckTCPProtocol Then
SendBufferedDataTCP
Else
SendBufferedDataUDP
End If
End Sub
'Send buffered data if we are using UDP protocol.
Private Sub SendBufferedDataUDP()
Dim lngAddress As Long
Dim udtSockAddr As sockaddr_in
Dim arrData() As Byte
Dim lngBufferLength As Long
Dim lngResult As Long
Dim lngErrorCode As Long
Dim strTemp As String
lngAddress = ResolveIfHostnameSync(m_strRemoteHost, strTemp, lngErrorCode)
If lngErrorCode <> 0 Then
m_strSendBuffer = ""
If lngErrorCode = WSAEAFNOSUPPORT Then
Err.Raise lngErrorCode, "CSocketMaster.SendBufferedDataUDP", GetErrorDescription(lngErrorCode)
Else
Err.Raise sckInvalidArg, "CSocketMaster.SendBufferedDataUDP", "Invalid argument"
End If
End If
With udtSockAddr
.sin_addr = lngAddress
.sin_family = AF_INET
.sin_port = api_htons(modSocketMaster.UnsignedToInteger(m_lngRemotePort))
End With
lngBufferLength = Len(m_strSendBuffer)
arrData() = StrConv(m_strSendBuffer, vbFromUnicode)
m_strSendBuffer = ""
lngResult = api_sendto(m_lngSocketHandle, arrData(0), lngBufferLength, 0&, udtSockAddr, LenB(udtSockAddr))
If lngResult = SOCKET_ERROR Then
lngErrorCode = Err.LastDllError
m_enmState = sckError: If ShowDebug Then Debug.Print "STATE: sckError"
Dim blnCancelDisplay As Boolean
blnCancelDisplay = True
RaiseEvent Error(lngErrorCode, GetErrorDescription(lngErrorCode), 0, "CSocketMaster.SendBufferedDataUDP", "", 0, blnCancelDisplay)
If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.SendBufferedDataUDP"
End If
End Sub
'Send buffered data if we are using TCP protocol.
Private Sub SendBufferedDataTCP()
Dim arrData() As Byte
Dim lngBufferLength As Long
Dim lngResult As Long
Dim lngTotalSent As Long
Do Until lngResult = SOCKET_ERROR Or Len(m_strSendBuffer) = 0
lngBufferLength = Len(m_strSendBuffer)
If lngBufferLength > m_lngSendBufferLen Then
lngBufferLength = m_lngSendBufferLen
arrData() = StrConv(Left$(m_strSendBuffer, m_lngSendBufferLen), vbFromUnicode)
Else
arrData() = StrConv(m_strSendBuffer, vbFromUnicode)
End If
lngResult = api_send(m_lngSocketHandle, arrData(0), lngBufferLength, 0&)
If lngResult = SOCKET_ERROR Then
Dim lngErrorCode As Long
lngErrorCode = Err.LastDllError
If lngErrorCode = WSAEWOULDBLOCK Then
If ShowDebug Then Debug.Print "WARNING: Send buffer full, waiting..."
If lngTotalSent > 0 Then RaiseEvent SendProgress(lngTotalSent, Len(m_strSendBuffer))
Else
m_enmState = sckError: If ShowDebug Then Debug.Print "STATE: sckError"
Dim blnCancelDisplay As Boolean
blnCancelDisplay = True
RaiseEvent Error(lngErrorCode, GetErrorDescription(lngErrorCode), 0, "CSocketMaster.SendBufferedData", "", 0, blnCancelDisplay)
If blnCancelDisplay = False Then MsgBox GetErrorDescription(lngErrorCode), vbOKOnly, "CSocketMaster.SendBufferedData"
End If
Else
If ShowDebug Then Debug.Print "OK Bytes sent: " & lngResult
lngTotalSent = lngTotalSent + lngResult
If Len(m_strSendBuffer) > lngResult Then
m_strSendBuffer = Mid$(m_strSendBuffer, lngResult + 1)
Else
If ShowDebug Then Debug.Print "OK Finished SENDING"
m_strSendBuffer = ""
Dim lngTemp As Long
lngTemp = lngTotalSent
lngTotalSent = 0
RaiseEvent SendProgress(lngTemp, 0)
RaiseEvent SendComplete
End If
End If
Loop
End Sub
'This function retrieves data from the Winsock buffer
'into the class local buffer. The function returns number
'of bytes retrieved (received).
Private Function RecvDataToBuffer() As Long
Dim arrBuffer() As Byte
Dim lngBytesReceived As Long
Dim strBuffTemporal As String
ReDim arrBuffer(m_lngRecvBufferLen - 1)
lngBytesReceived = api_recv(m_lngSocketHandle, arrBuffer(0), m_lngRecvBufferLen, 0&)
If lngBytesReceived = SOCKET_ERROR Then
m_enmState = sckError: If ShowDebug Then Debug.Print "STATE: sckError"
Dim lngErrorCode As Long
lngErrorCode = Err.LastDllError
Err.Raise lngErrorCode, "CSocketMaster.RecvDataToBuffer", GetErrorDescription(lngErrorCode)
ElseIf lngBytesReceived > 0 Then
strBuffTemporal = StrConv(arrBuffer(), vbUnicode)
m_strRecvBuffer = m_strRecvBuffer & Left$(strBuffTemporal, lngBytesReceived)
RecvDataToBuffer = lngBytesReceived
End If
End Function
'Retrieves some socket options.
'If it is an UDP socket also sets SO_BROADCAST option.
Private Sub ProcessOptions()
Dim lngResult As Long
Dim lngBuffer As Long
Dim lngErrorCode As Long
If m_enmProtocol = sckTCPProtocol Then
lngResult = api_getsockopt(m_lngSocketHandle, SOL_SOCKET, SO_RCVBUF, lngBuffer, LenB(lngBuffer))
If lngResult = SOCKET_ERROR Then
lngErrorCode = Err.LastDllError
Err.Raise lngErrorCode, "CSocketMaster.ProcessOptions", GetErrorDescription(lngErrorCode)
Else
m_lngRecvBufferLen = lngBuffer
End If
lngResult = api_getsockopt(m_lngSocketHandle, SOL_SOCKET, SO_SNDBUF, lngBuffer, LenB(lngBuffer))
If lngResult = SOCKET_ERROR Then
lngErrorCode = Err.LastDllError
Err.Raise lngErrorCode, "CSocketMaster.ProcessOptions", GetErrorDescription(lngErrorCode)
Else
m_lngSendBufferLen = lngBuffer
End If
Else
lngBuffer = 1
lngResult = api_setsockopt(m_lngSocketHandle, SOL_SOCKET, SO_BROADCAST, lngBuffer, LenB(lngBuffer))
lngResult = api_getsockopt(m_lngSocketHandle, SOL_SOCKET, SO_MAX_MSG_SIZE, lngBuffer, LenB(lngBuffer))
If lngResult = SOCKET_ERROR Then
lngErrorCode = Err.LastDllError
Err.Raise lngErrorCode, "CSocketMaster.ProcessOptions", GetErrorDescription(lngErrorCode)
Else
m_lngRecvBufferLen = lngBuffer
m_lngSendBufferLen = lngBuffer
End If
End If
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -