VBA Windows Socket Programming

nector

Member
Local time
Today, 08:52
Joined
Jan 21, 2020
Messages
462
After finishing working on the SQL server cloud and taking a course on TCP/IP protocol, I have decided to go back to WINSOCK or window sockets if you like that way. I have constructed the data structure based on the C++ guide on network and then translate it into VBA.

Yes, at the beginning there were a lot of errors, but I had to clear them step by step being a fellow chartered accountant, I thought that was the best method for me to handle such problems. The first project similar to Winsock called serial COM port is working perfect no one is complaining about it, but this one will continue to be used for local area network with some gadgets attached to the target computers as you know the COM ports cannot be shared over the internet without buying expensive firmware.

My new commands for Winsock are purely based on the module I have translated and amended on my computer, now I intend to start testing this one fulltime in May 2023.

The reasons why I’m writing this is to ask for assistance on the issues below:

  • Can someone audit the sequence of my commands whether they are in agreement with the photo attached. Kindly note that the photo has also an error on the send and receive commands. The send command was supposed to come first then followed by the receive command.
  • The hostname & port number here with my understanding it represents the server IP address & port number (The IP address of the gadget and port number where to send data)
  • For the client side, the port number is supposed to be assigned automatically by the O/S while the IP address is the same server IP address.
Where you see a mistake kindly point it out, I’M NOT ASKING FOR ANY FREE CODE, I will do it on my own, that is the best way to learn not just copying.

Thank you in advance for any contribution!



Regards

Christopher

From Southern Africa

Code:
Function initWinsock() As Boolean ' {
'Initialize winsock here
Dim wsaVersion As Long
wsaVersion = 257
Dim rc As Long
Dim wsa As WSADATA
rc = WSAStartup(wsaVersion, wsa)
If rc <> 0 Then
initWinsock = False
Exit Function
End If
initWinsock = True
End Function ' }
Function OpenSocket(ByVal Hostname As String, ByVal PortNumber As Integer) As Integer
    Dim x As Long
    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 = w_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
'Binding a socket
    Dim rc As Long
    rc = bind(socketId, I_SocketAddress, 16)
    If rc <> 0 Then
       MsgBox "Could not bind, error = " & WSAGetLastError()
       Exit Function
    End If
    rc = listen(socketId, 10) ' 10 = backlog
    If rc <> 0 Then
       MsgBox "Could not listen"
    End If
End Function
Public Function acceptConnections(serverSocket As Long) ' {

    Dim clientSocket As Long

    Dim i As Long
    i = 0

    Do While i < 200
       i = i + 1
       Sleep 100
       Debug.Print "i = " & i

       clientSocket = getClientSocket(serverSocket)

       If clientSocket = 0 Then
          GoTo SKIP_THIS_ITERATION
       End If

       Dim reqText As String
       reqText = getStringFromSocket(clientSocket)

       Dim textResponse As String
       textResponse = "HTTP/1.1 200 OK" & Chr(10)
       textResponse = textResponse & "Content-Type: text/html" & Chr(10)
       textResponse = textResponse & Chr(10)
       textResponse = textResponse & "<!doctype html>" & Chr(10)
       textResponse = textResponse & "<html><body>Request was:<br><code><pre>"
       textResponse = textResponse & reqText
       textResponse = textResponse & "</pre></code></body></html>"

       send clientSocket, ByVal textResponse, Len(textResponse), 0

       closesocket clientSocket

SKIP_THIS_ITERATION:
    Loop

End Function ' }

Public Function getStringFromSocket(s As Long) ' {
    Dim message   As String
    Dim buffer    As String * 2048
    Dim readBytes As Long

    message = ""

    Do
        buffer = ""
        readBytes = recv(s, buffer, Len(buffer), 0)

        If readBytes > 0 Then
           message = message & Trim(buffer)
        End If
    Loop While readBytes > 0

    getStringFromSocket = Trim(message)

End Function ' }

Function getClientSocket(serverSocket As Long) As Long ' {
    Dim fdSet As fd_set
    Dim emptyFdSet As fd_set
    Dim rc As Integer

    FD_ZERO fdSet
    FD_SET_ serverSocket, fdSet

    Dim timeOutMs As Long
    timeOutMs = 500

    Dim timeout  As timeval
    timeout.tv_sec = timeOutMs / 1000
    timeout.tv_usec = timeOutMs Mod 1000

    rc = select_(serverSocket, fdSet, emptyFdSet, emptyFdSet, timeout)
    If rc = 0 Then
       getClientSocket = 0
       Exit Function
    End If

    Dim socketAddress As sockaddr
    getClientSocket = accept(serverSocket, socketAddress, 16)

    If getClientSocket = -1 Then
       getClientSocket = 0
       Exit Function
    End If

    rc = setsockopt(getClientSocket, SOL_SOCKET, SO_RCVTIMEO, timeOutMs, 4)
End Function ' }

Function SendCommand(ByVal command As String) As Integer
' our communication command...

    Dim strSend As String
    Dim count As Integer
    strSend = command + vbCrLf
   
    count = send(socketId, ByVal strSend, Len(strSend), 0)
   
    If count = SOCKET_ERROR Then
        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
' our recv function..

    Dim c As String * 1
    Dim length As Integer
    Dim count 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

Public Function CloseConnection()
Dim x As Long
' we close our connection here
    x = closesocket(socketId)
    If x = SOCKET_ERROR Then
        MsgBox ("ERROR: closesocket = " + Str$(x))
        Exit Function
    End If
End Function

Public Function EndIt()
Dim x As Long
    'Shutdown Winsock DLL
    x = WSACleanup()
End Function



TCP Chart 2023.png
 

Users who are viewing this thread

Back
Top Bottom