Excel with Listening Socket

Reca

New Member
Joined
Feb 17, 2011
Messages
2
Hi,

Can anyone advise and help how to write VBA in excel such that there is a Listening Socket continuously listen on the background and once a string is received, it is written to a certain cell in the excel spreadsheet.

the user can continue to work on the excel spreadsheet while the VBA continue to listen to incoming string on the background.

Thanks in advance....

Reca
 

Excel Facts

Select all contiguous cells
Pressing Ctrl+* (asterisk) will select the "current region" - all contiguous cells in all directions.
Hi John,

Thanks for the prompt reply. Really appreciate that. I have actually tried that component. It works fine when I use

Dim withEvents... in the form.

When I try to put that into the VBA code without the form, it just don't trigger the event. I thought this component can work without a form.

However, I need the listening socket to be running in the background and listening rather than in a form. Is there a way to do that?

Can you kindly show me some source code if possible. Much appreciated.

Regards

Reca
 
Upvote 0
Basically, put the form code into a class module and, in a standard module, create a module-level object variable that points to an instance of the class and which will exist throughout the Excel session. Here's how, including a few supporting properties and methods.

Put the following code in a new class module, renamed to CWinsock:
Code:
'CWinsock.  Class for OstroSoft Winsock Component, based on http://www.ostrosoft.com/oswinsck/oswinsck_vba.asp

Option Explicit

Private WithEvents wsTCP As OSWINSCK.Winsock
Private pUpdateCell As Range        'cell to be updated when data is received

Private Sub Class_Initialize()
    Set wsTCP = New OSWINSCK.Winsock
    Set pUpdateCell = Nothing
End Sub

Private Sub Class_Terminate()
    If wsTCP.State = sckConnected Then
        wsTCP.CloseWinsock
    End If
    Set wsTCP = Nothing
    Set pUpdateCell = Nothing
    
    Debug.Print "Finished"
End Sub

'-------------- Methods -------------

Public Sub Connect(host As String, port As Long)
    wsTCP.Connect host, port
End Sub

Public Sub Disconnect()
    If wsTCP.State = sckConnected Then
        wsTCP.CloseWinsock
    End If
End Sub

'-------------- Properties -------------

Public Property Set UpdateCell(cell As Range)
    Set pUpdateCell = cell
End Property

Public Property Get UpdateCell() As Range
    Set UpdateCell = pUpdateCell
End Property

'-------------- OSWINSCK.Winsock events -------------

Private Sub wsTCP_OnClose()
    If wsTCP.State = sckOpen Then
        wsTCP.SendData "Closing"
    End If
    wsTCP.CloseWinsock
End Sub

Private Sub wsTCP_OnConnect()
    Debug.Print "OnConnect"
End Sub

Private Sub wsTCP_OnDataArrival(ByVal bytesTotal As Long)
    Dim sBuffer As String
    
    wsTCP.GetData sBuffer
    
    If Not pUpdateCell Is Nothing Then
        pUpdateCell.Value = pUpdateCell.Value & sBuffer
    Else
        MsgBox "UpdateCell property not set"
    End If
End Sub

Private Sub wsTCP_OnError(ByVal Number As Integer, _
    Description As String, ByVal Scode As Long, ByVal Source As String, _
    ByVal HelpFile As String, ByVal HelpContext As Long, _
    CancelDisplay As Boolean)
    
    MsgBox "OSWINSCK.Winsock error " & Number & ": " & Description
End Sub

Private Sub wsTCP_OnStatusChanged(ByVal Status As String)
    Debug.Print Status
End Sub
Put the following code in standard module renamed to modReceiver, though its name doesn't matter:
Code:
'VBA project needs reference to OstroSoft Winsock Component - http://www.ostrosoft.com/oswinsck.asp

Option Explicit

Private WsReceiver As CWinsock

Public Sub Start_Receiver()

    If WsReceiver Is Nothing Then
        Set WsReceiver = New CWinsock
    End If
    
    'Set the cell to be updated when data is received
    
    Set WsReceiver.UpdateCell = Sheets("Sheet1").Range("A1")
    WsReceiver.UpdateCell.Value = ""
    
    'Connect to remote host on specific port
    
    WsReceiver.Connect "localhost", 79
    
End Sub

Public Sub Stop_Receiver()

    If Not WsReceiver Is Nothing Then
        WsReceiver.Disconnect
    End If
    Set WsReceiver = Nothing
    
End Sub
If you want the receiver to be ready and waiting for data when you open the workbook and stop when you close the workbook, then put the following code in the ThisWorkbook module:
Code:
Option Explicit

Private Sub Workbook_Open()
    Start_Receiver
End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Stop_Receiver
End Sub
Otherwise call Start_Receiver from your own procedure, e.g. a command button click event. My Start_Receiver reads data from localhost on port 79 and I used Microsoft HyperTerminal to test it.
 
Upvote 0
It's great!I can read data sent through tcp. However, i need to read data from UDP.I read the Ostrosoft documentation, and it's written about protocol properties.object.Protocol As ProtocolConstantsValuename0 sckTCPProtocol TCP Protocol1 sckUDPProtocol UDP ProtocolHowever, I can't figure out how to write the code in the class module to set the properties to 1.Can you help me on this one?Thanks
 
Upvote 0
Basically, put the form code into a class module and, in a standard module, create a module-level object variable that points to an instance of the class and which will exist throughout the Excel session. Here's how, including a few supporting properties and methods.

Put the following code in a new class module, renamed to CWinsock:
Code:
'CWinsock.  Class for OstroSoft Winsock Component, based on http://www.ostrosoft.com/oswinsck/oswinsck_vba.asp

Option Explicit

Private WithEvents wsTCP As OSWINSCK.Winsock
Private pUpdateCell As Range        'cell to be updated when data is received

Private Sub Class_Initialize()
    Set wsTCP = New OSWINSCK.Winsock
    Set pUpdateCell = Nothing
End Sub

Private Sub Class_Terminate()
    If wsTCP.State = sckConnected Then
        wsTCP.CloseWinsock
    End If
    Set wsTCP = Nothing
    Set pUpdateCell = Nothing
  
    Debug.Print "Finished"
End Sub

'-------------- Methods -------------

Public Sub Connect(host As String, port As Long)
    wsTCP.Connect host, port
End Sub

Public Sub Disconnect()
    If wsTCP.State = sckConnected Then
        wsTCP.CloseWinsock
    End If
End Sub

'-------------- Properties -------------

Public Property Set UpdateCell(cell As Range)
    Set pUpdateCell = cell
End Property

Public Property Get UpdateCell() As Range
    Set UpdateCell = pUpdateCell
End Property

'-------------- OSWINSCK.Winsock events -------------

Private Sub wsTCP_OnClose()
    If wsTCP.State = sckOpen Then
        wsTCP.SendData "Closing"
    End If
    wsTCP.CloseWinsock
End Sub

Private Sub wsTCP_OnConnect()
    Debug.Print "OnConnect"
End Sub

Private Sub wsTCP_OnDataArrival(ByVal bytesTotal As Long)
    Dim sBuffer As String
  
    wsTCP.GetData sBuffer
  
    If Not pUpdateCell Is Nothing Then
        pUpdateCell.Value = pUpdateCell.Value & sBuffer
    Else
        MsgBox "UpdateCell property not set"
    End If
End Sub

Private Sub wsTCP_OnError(ByVal Number As Integer, _
    Description As String, ByVal Scode As Long, ByVal Source As String, _
    ByVal HelpFile As String, ByVal HelpContext As Long, _
    CancelDisplay As Boolean)
  
    MsgBox "OSWINSCK.Winsock error " & Number & ": " & Description
End Sub

Private Sub wsTCP_OnStatusChanged(ByVal Status As String)
    Debug.Print Status
End Sub
Put the following code in standard module renamed to modReceiver, though its name doesn't matter:
Code:
'VBA project needs reference to OstroSoft Winsock Component - http://www.ostrosoft.com/oswinsck.asp

Option Explicit

Private WsReceiver As CWinsock

Public Sub Start_Receiver()

    If WsReceiver Is Nothing Then
        Set WsReceiver = New CWinsock
    End If
  
    'Set the cell to be updated when data is received
  
    Set WsReceiver.UpdateCell = Sheets("Sheet1").Range("A1")
    WsReceiver.UpdateCell.Value = ""
  
    'Connect to remote host on specific port
  
    WsReceiver.Connect "localhost", 79
  
End Sub

Public Sub Stop_Receiver()

    If Not WsReceiver Is Nothing Then
        WsReceiver.Disconnect
    End If
    Set WsReceiver = Nothing
  
End Sub
If you want the receiver to be ready and waiting for data when you open the workbook and stop when you close the workbook, then put the following code in the ThisWorkbook module:
Code:
Option Explicit

Private Sub Workbook_Open()
    Start_Receiver
End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Stop_Receiver
End Sub
Otherwise call Start_Receiver from your own procedure, e.g. a command button click event. My Start_Receiver reads data from localhost on port 79 and I used Microsoft HyperTerminal to test it.

Hi John ?

Unfortunately I couldn't get your code to work on my computer (Office2016).
Unfortunately, I am still a VBA beginner and cannot integrate the CWinsock ...

Is it possible in a similar way to generate a TCP server in Excel (VBA), which simply writes the incoming TCP messages one below the other in an Excel sheet?
The measurement data (voltages ala "234.5") come every second from an ESP32 that is connected to the laptop's hotspot via WiFi.

I imagine a UserForm which simply has a start and a stop button.

How do I do it?
 
Upvote 0
Is it possible in a similar way to generate a TCP server in Excel (VBA), which simply writes the incoming TCP messages one below the other in an Excel sheet?
The measurement data (voltages ala "234.5") come every second from an ESP32 that is connected to the laptop's hotspot via WiFi.
The Visual Basic (server) example at OstroSoft Winsock Component shows how to write a TCP server. The code is for Visual Basic userforms (a TCP server form for multiple clients and a TCP client form) and can be easily ported to VBA. The main changes needed for VBA userforms are renaming the VB Private Sub Form_Load() and Private Sub Form_Unload() procedures to Private Sub UserForm_Initialize() and Private Sub UserForm_Terminate().

The VB source code is also available at GitHub - ostrosoft/vb6-tcp-client-server: VB6 CLient-Server example for OstroSoft Winsock Component.

I imagine a UserForm which simply has a start and a stop button.

In your case you want a VBA TCP server which communicates with a single client and writes data/messages to an Excel sheet. For this, a server userform isn't really needed because the Start and Stop buttons can be placed on the sheet instead, and the TCP client userform isn't needed because the data is coming from an external device.

Standard module - e.g. Module1.
VBA Code:
Option Explicit

Dim TCPserver As clsTCPServer

Public Sub Start_Server()
    
    Set TCPserver = New clsTCPServer
    
    With ActiveSheet
        If IsEmpty(.Range("A1").Value) Then
            .Range("A1:B1").Value = Array("Time", "Event")
            Set TCPserver.EventCell = .Range("A2")
        Else
            Set TCPserver.EventCell = .Cells(.Rows.Count, 1).End(xlUp).Offset(1)
        End If
    End With
    
    'Start server on port 22
    
    TCPserver.StartServer 22
    
End Sub


Public Sub Stop_Server()
    
    If Not TCPserver Is Nothing Then
        TCPserver.StopServer
    End If
    
End Sub

Public Sub Clear_Events()

    With ActiveSheet
        .Rows("2:" & .Rows.Count).ClearContents
        .Range("A2").Select
    End With
    
End Sub
Insert 3 form control command buttons (Start, Stop and Clear Events) on the sheet and assign each to the respective procedure in the above code. The server listens on TCP port 22 - change this port number in the above code if necessary.

Class module, renamed to clsTCPServer.
VBA Code:
'Class Module - clsTCPServer

Option Explicit

Dim WithEvents server As OSWINSCK.Winsock
Dim TCPlistener As clsTCPServerListener
Dim pEventCell As Range

'======== Properties ========

Public Property Get EventCell() As Range
    Set EventCell = pEventCell
End Property
Public Property Set EventCell(cell As Range)
    Set pEventCell = cell
End Property


'======== Public methods ========

Public Sub StartServer(port As Long)
    Set server = New OSWINSCK.Winsock
    server.LocalPort = port
    server.Listen
    LogEvent "Server is listening on port " & server.LocalPort
End Sub

Public Sub StopServer()
    If Not TCPlistener Is Nothing Then
        TCPlistener.CloseWinsock
        Set TCPlistener = Nothing
        LogEvent "Listener closed"
    End If
    server.CloseWinsock
    Set server = Nothing
    LogEvent "Server closed"
End Sub

Public Sub OnDataArrival(ByVal bytesTotal As Long)
    
    'Called by listener_OnDataArrival in clsTCPServerListener when the listener receives data
    
    Dim dataReceived As String
    Dim dataSent As String
    
    LogEvent "Listener OnDataArrival bytesTotal = " & bytesTotal
    
    TCPlistener.GetData dataReceived
    LogEvent "Listener Received: " & dataReceived
    
    dataSent = "Server sent: " & dataReceived
    TCPlistener.SendData dataSent
    LogEvent "Server SendData: " & dataSent
    
End Sub

Public Sub OnStatusChanged(ByVal Status As String)
    
    'Called by listener_OnStatusChanged in clsTCPServerListener when the listener's status changes, e.g. connection request, data arrival, send progress, send complete
    
    LogEvent "Listener OnStatusChanged Status = " & Status

End Sub

Public Sub OnClose()

    'Called by listener_OnClose in clsTCPServerListener when the client closes the connection
    
    LogEvent "Listener OnClose"
    TCPlistener.CloseWinsock
    
End Sub

Public Sub OnError(ByVal Index As Long, ByVal Number As Long, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)

End Sub


'======== Events raised by server As OSWINSCK.Winsock ========

Private Sub server_OnConnectionRequest(ByVal requestID As Long)

    'Called when this server receives a connection request from the client
    
    Dim dataSent As String
    
    LogEvent "server_OnConnectionRequest requestID = " & requestID
    
    Set TCPlistener = New clsTCPServerListener
    TCPlistener.SetCallback Me
    
    TCPlistener.LocalPort = server.LocalPort
    TCPlistener.Accept requestID
    
    dataSent = "Connection request accepted by listener" & vbCrLf
    TCPlistener.SendData dataSent
    LogEvent "Server SendData: " & dataSent
    
End Sub

Private Sub server_OnStatusChanged(ByVal Status As String)
    'Called when this server's Status changes, e.g. connection request from the client
    LogEvent "server_OnStatusChanged Status = " & Status
End Sub

'======== Private methods ========

Private Sub LogEvent(strText As String)

    'Write time and event text to sheet
    
    Dim lr As Long, sr As Long
    
    With EventCell.Worksheet
        lr = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
        Set EventCell = .Cells(lr, 1)
    End With
    EventCell.Resize(, 2) = Array(Time, strText)
    
    sr = lr - ActiveWindow.VisibleRange.Rows.Count + 2
    If sr < 1 Then sr = 1
    ActiveWindow.ScrollRow = sr

End Sub


Private Function Get_State(socketState As StateConstants) As String
    Select Case socketState
        Case StateConstants.sckClosed:            Get_State = "Connection closed"
        Case StateConstants.sckOpen:              Get_State = "Open"
        Case StateConstants.sckListening:         Get_State = "Listening for incoming connections"
        Case StateConstants.sckConnectionPending: Get_State = "Lonnection pending"
        Case StateConstants.sckResolvingHost:     Get_State = "Resolving remote host name"
        Case StateConstants.sckHostResolved:      Get_State = "Remote host name successfully resolved"
        Case StateConstants.sckConnecting:        Get_State = "Connecting to remote host"
        Case StateConstants.sckConnected:         Get_State = "Connected to remote host"
        Case StateConstants.sckClosing:           Get_State = "Connection is closing"
        Case StateConstants.sckError:             Get_State = "Error occurred"
    End Select
End Function

Class module, renamed to clsTCPServerListener. This is based on vb6-tcp-client-server/clsTCPServerListener.cls at master · ostrosoft/vb6-tcp-client-server, with the code to handle multiple TCP clients removed.
VBA Code:
'Class Module - clsTCPServerListener

Option Explicit

Private m_Callback As clsTCPServer
Private WithEvents listener As OSWINSCK.Winsock

'===== PROPERTIES =====
Public Property Get BytesReceived() As Long
  BytesReceived = listener.BytesReceived
End Property

Public Property Get LocalHostName() As String
  LocalHostName = listener.LocalHostName
End Property

Public Property Get LocalIP() As String
  LocalIP = listener.LocalIP
End Property

Public Property Get LocalPort() As Long
  LocalPort = listener.LocalPort
End Property
Public Property Let LocalPort(NewValue As Long)
  listener.LocalPort = NewValue
End Property

Public Property Get Protocol() As ProtocolConstants
  Protocol = listener.Protocol
End Property
Public Property Let Protocol(NewValue As ProtocolConstants)
  listener.Protocol = NewValue
End Property

Public Property Get RemoteHost() As String
  RemoteHost = listener.RemoteHost
End Property
Public Property Let RemoteHost(NewValue As String)
  listener.RemoteHost = NewValue
End Property

Public Property Get RemoteHostIP() As String
  RemoteHostIP = listener.RemoteHostIP
End Property

Public Property Get RemotePort() As Long
  RemotePort = listener.RemotePort
End Property
Public Property Let RemotePort(NewValue As Long)
  listener.RemotePort = NewValue
End Property

Public Property Get SocketHandle() As Long
  SocketHandle = listener.SocketHandle
End Property

Public Property Get State() As StateConstants
  State = listener.State
End Property

Public Property Get Status() As String
  Status = listener.Status
End Property
Public Property Let Status(ByVal strTemp As String)
  listener.Status = strTemp
End Property

Public Property Get Tag() As String
  Tag = listener.Tag
End Property
Public Property Let Tag(ByVal vNewValue As String)
  listener.Tag = vNewValue
End Property

'===== METHODS =====
Public Sub Accept(requestID As Long)
    listener.Accept (requestID)
End Sub

Public Sub CloseWinsock()
    listener.CloseWinsock
End Sub

Public Sub Connect(Optional RemoteHost As Variant, Optional RemotePort As Variant)
    listener.Connect RemoteHost, RemotePort
End Sub

Public Sub GetData(data As Variant, Optional vtype As Variant, Optional maxLen As Variant)
    listener.GetData data, vtype, maxLen
End Sub

Public Sub SendData(data As Variant)
    listener.SendData data
End Sub

Public Sub SetCallback(ByRef TCPserver As clsTCPServer)
    Set m_Callback = TCPserver
End Sub

Private Sub Class_Initialize()
    Set listener = New OSWINSCK.Winsock
End Sub

Private Sub Class_Terminate()
    Set listener = Nothing
End Sub

Private Sub listener_OnClose()
    m_Callback.OnClose
End Sub

Private Sub listener_OnDataArrival(ByVal bytesTotal As Long)
    m_Callback.OnDataArrival bytesTotal
End Sub

Private Sub listener_OnStatusChanged(ByVal Status As String)
    m_Callback.OnStatusChanged Status
End Sub
NOTE - as mentioned, you must rename the two class modules to the specified names, otherwise the code won't compile.

In the clsTCPServer class, the LogEvent procedure writes the current time and a text string to the next row in the Excel sheet. I have written clsTCPServer for diagnostic purposes, therefore LogEvent is called in many places in the class, not just for the data received by the running TCP Server but also for events and status changes, to show exactly what the server is doing.

Public Sub OnDataArrival(ByVal bytesTotal As Long) is the procedure which receives data from the TCP client, by calling the Winsock GetData method. It also responds to the client by sending the same data by calling the Winsock SendData method - remove this line if you don't need to respond to the client.
 
Upvote 0

Forum statistics

Threads
1,214,653
Messages
6,120,755
Members
448,989
Latest member
mariah3

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top