cWinsock UDP Programming Guide
📖 Table of Contents
- Overview
- UDP Basic Programming
- UDP Server Virtual Client
- UDP Broadcast and Multicast
- Advanced Features
- Common Issues
Overview
UDP (User Datagram Protocol) is a connectionless, unreliable transmission protocol, suitable for scenarios requiring real-time performance and tolerating some data loss.
UDP Characteristics
- ✅ Connectionless: No need to establish connection
- ✅ Low latency: No connection overhead
- ✅ Simple and efficient: Small protocol overhead
- ✅ Broadcast support: Can send to multiple receivers simultaneously
- ❌ Unreliable: Doesn't guarantee data arrival, ordering, or integrity
- ❌ No flow control: May cause network congestion
Use Cases
- Real-time gaming
- Video streaming
- Audio calls
- DNS queries
- Network discovery
- IoT device communication
UDP Basic Programming
UDP Client
' Declare UDP object
Private WithEvents m_oUdp As cWinsock
' Initialize
Private Sub Form_Load()
Set m_oUdp = New cWinsock
m_oUdp.Protocol = sckUDPProtocol
m_oUdp.Bind 0 ' 0 means system auto-assigns port
Debug.Print "UDP client bound to port: " & m_oUdp.LocalPort
End Sub
' Send data
Private Sub cmdSend_Click()
' Set remote address and port
m_oUdp.RemoteHost = "127.0.0.1"
m_oUdp.RemotePort = 8888
' Send data
m_oUdp.SendData "Hello, UDP!"
Debug.Print "Sent to " & m_oUdp.RemoteHost & ":" & m_oUdp.RemotePort
End Sub
' Receive data
Private Sub m_oUdp_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
' Receive data
Client.GetData sData
Debug.Print "Received data (" & bytesTotal & " bytes): " & sData
Debug.Print "From: " & Client.RemoteHostIP & ":" & Client.RemotePort
End Sub
' Close
Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
m_oUdp.Close_
End SubUDP Server
' Declare UDP server object
Private WithEvents m_oUdpServer As cWinsock
' Start server
Private Sub cmdStart_Click()
Set m_oUdpServer = New cWinsock
m_oUdpServer.Protocol = sckUDPProtocol
m_oUdpServer.Bind 8888
Debug.Print "UDP server bound to port: 8888"
End Sub
' Data arrival
Private Sub m_oUdpServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
' Receive data
Client.GetData sData
Debug.Print "Received from " & Client.RemoteHostIP & ":" & Client.RemotePort
Debug.Print "Content: " & sData
' Reply
Client.SendData "Reply: " & sData
Debug.Print "Replied"
End Sub
' Close
Private Sub cmdStop_Click()
m_oUdpServer.Close_
Debug.Print "UDP server stopped"
End SubUDP Server Virtual Client
Overview
UDP is a connectionless protocol, but cWinsock creates virtual client objects for each different remote address:port combination, simulating connection behavior.
How It Works
First time receiving data from 192.168.1.100:5000
↓
Create virtual client object, Tag = "192.168.1.100:5000"
↓
Trigger ConnectionRequest event
↓
Trigger DataArrival event
↓
Can reply to that virtual clientExample Code
Private WithEvents m_oUdpServer As cWinsock
' Start server
Private Sub cmdStart_Click()
Set m_oUdpServer = New cWinsock
m_oUdpServer.Protocol = sckUDPProtocol
m_oUdpServer.Bind 8888
Debug.Print "UDP server started"
End Sub
' New connection request (first time receiving data from some address:port)
Private Sub m_oUdpServer_ConnectionRequest(Client As cWinsock, ByRef DisConnect As Boolean)
Debug.Print "New UDP client: " & Client.RemoteHostIP & ":" & Client.RemotePort
Debug.Print "Tag: " & Client.Tag
' Can intercept here
If IsInBlacklist(Client.RemoteHostIP) Then
Debug.Print "Reject blacklist IP: " & Client.RemoteHostIP
DisConnect = True
End If
End Sub
' Data arrival
Private Sub m_oUdpServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
' Receive data
Client.GetData sData
Debug.Print "Data from " & Client.Tag & ": " & sData
' Reply directly to that virtual client
Client.SendData "Echo: " & sData
End Sub
' Connection closed (virtual client timeout)
Private Sub m_oUdpServer_CloseEvent(Client As cWinsock)
Debug.Print "UDP client " & Client.Tag & " disconnected"
' Update client list
UpdateClientList
End Sub
' Update client list
Private Sub UpdateClientList()
lstClients.Clear
lblCount.Caption = m_oUdpServer.ClientCount
Dim oClient As cWinsock
For Each oClient In m_oUdpServer.Clients
lstClients.AddItem oClient.Tag & " - " & oClient.RemoteHostIP & ":" & oClient.RemotePort
Next
End SubVirtual Client Timeout Handling
Private Sub tmrCleanup_Timer()
Dim oClient As cWinsock
Dim tSession As tSessionData
For Each oClient In m_oUdpServer.Clients
tSession = oClient.UserData
' Check timeout (5 minutes no activity)
If DateDiff("s", tSession.LastActivity, Now) > 300 Then
Debug.Print "Clean up timeout client: " & oClient.Tag
oClient.Close_
End If
Next
End Sub
Private Sub m_oUdpServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
' Update activity time
Dim tSession As tSessionData
If IsEmpty(Client.UserData) Then
tSession.FirstSeen = Now
Else
tSession = Client.UserData
End If
tSession.LastActivity = Now
Client.UserData = tSession
' Process data...
ProcessData Client, sData
End SubUDP Broadcast and Multicast
Broadcast
' Broadcast to LAN
Private Sub cmdBroadcast_Click()
' Bind to any port
m_oUdp.Bind 0
' Set broadcast address
m_oUdp.RemoteHost = "255.255.255.255"
m_oUdp.RemotePort = 9999
' Send broadcast message
m_oUdp.SendData "Broadcast message"
Debug.Print "Sent broadcast"
End Sub
' Receive broadcast
Private Sub m_oUdp_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
Debug.Print "Received broadcast: " & sData
Debug.Print "From: " & Client.RemoteHostIP & ":" & Client.RemotePort
End SubLAN Device Discovery
' Send discovery request
Private Sub cmdDiscover_Click()
m_oUdp.RemoteHost = "255.255.255.255"
m_oUdp.RemotePort = 9999
m_oUdp.SendData "DISCOVER_SERVERS"
End Sub
' Server responds to discovery
Private Sub m_oUdpServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
If sData = "DISCOVER_SERVERS" Then
' Respond with own info
Client.SendData "SERVER_INFO:" & GetLocalIP() & ":" & m_oUdpServer.LocalPort
End If
End Sub
' Client collects responses
Private Sub m_oUdp_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
If Left$(sData, 12) = "SERVER_INFO:" Then
Dim sInfo As String
sInfo = Mid$(sData, 13)
Debug.Print "Discovered server: " & sInfo
' Add to list
lstServers.AddItem sInfo
End If
End SubMulticast (Groupcast)
' Join multicast group
Private Sub JoinMulticastGroup(ByVal sGroupIP As String, ByVal lPort As Long)
' Note: cWinsock doesn't directly support multicast
' Need to use underlying socket API or cAsyncSocket
' Basic usage demonstrated here
m_oUdp.Bind lPort
m_oUdp.RemoteHost = sGroupIP
m_oUdp.RemotePort = lPort
Debug.Print "Joined multicast group: " & sGroupIP
End Sub
' Send to multicast group
Private Sub cmdSendMulticast_Click()
m_oUdp.SendData "Multicast message"
Debug.Print "Sent to multicast group"
End SubAdvanced Features
✅ Reliable UDP (with Acknowledgment)
' Reliable UDP sending
Private Type tReliablePacket
Sequence As Long ' Sequence number
Total As Long ' Total packets
Index As Long ' Current packet index
Data As String ' Data
Acked As Boolean ' Acknowledged
Timestamp As Double ' Send time
End Type
Private m_lSequence As Long
Private m_lWindowSize As Long
' Send data
Private Sub SendReliable(ByVal sData As String)
Dim lChunkSize As Long
lChunkSize = 1000 ' 1KB per packet
Dim lTotalChunks As Long
lTotalChunks = (Len(sData) \ lChunkSize) + 1
Dim i As Long
For i = 0 To lTotalChunks - 1
Dim lStart As Long
lStart = i * lChunkSize + 1
Dim lEnd As Long
lEnd = Min(lStart + lChunkSize - 1, Len(sData))
Dim sChunk As String
sChunk = Mid$(sData, lStart, lEnd - lStart + 1)
' Send packet
m_oUdp.SendData "PKT:" & m_lSequence & ":" & lTotalChunks & ":" & i & ":" & sChunk
Debug.Print "Sent packet " & i + 1 & "/" & lTotalChunks
m_lSequence = m_lSequence + 1
' Control send rate
If (i + 1) Mod m_lWindowSize = 0 Then
Sleep 50 ' Wait when window full
End If
Next
End Sub
' Receive and acknowledge
Private Sub m_oUdp_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
If Left$(sData, 4) = "PKT:" Then
' Parse packet
Dim sParts() As String
sParts = Split(Mid$(sData, 5), ":")
Dim lSeq As Long
Dim lTotal As Long
Dim lIndex As Long
Dim sPayload As String
lSeq = CLng(sParts(0))
lTotal = CLng(sParts(1))
lIndex = CLng(sParts(2))
sPayload = sParts(3)
Debug.Print "Received packet " & lIndex + 1 & "/" & lTotal & " (sequence: " & lSeq & ")"
' Send acknowledgment
Client.SendData "ACK:" & lSeq & ":" & lIndex
' Process data...
ProcessPacket lSeq, lIndex, lTotal, sPayload
ElseIf Left$(sData, 4) = "ACK:" Then
' Received acknowledgment
Dim sAckParts() As String
sAckParts = Split(Mid$(sData, 5), ":")
Dim lAckSeq As Long
Dim lAckIndex As Long
lAckSeq = CLng(sAckParts(0))
lAckIndex = CLng(sAckParts(1))
' Mark as acknowledged
MarkPacketAcked lAckSeq, lAckIndex
Debug.Print "Received acknowledgment: " & lAckSeq & ":" & lAckIndex
End If
End Sub📊 Packet Reassembly
' Packet reassembly
Private Type tReassemblyBuffer
Packets() As String
ReceivedCount As Long
TotalCount As Long
End Type
Private m_oReassembly As Collection
' Initialize reassembly buffer
Private Sub InitReassembly(ByVal lSequence As Long, ByVal lTotal As Long)
Dim tBuffer As tReassemblyBuffer
ReDim tBuffer.Packets(0 To lTotal - 1) As String
tBuffer.ReceivedCount = 0
tBuffer.TotalCount = lTotal
m_oReassembly.Add tBuffer, CStr(lSequence)
End Sub
' Add packet
Private Sub AddPacket(ByVal lSequence As Long, ByVal lIndex As Long, ByVal sData As String)
Dim tBuffer As tReassemblyBuffer
On Error Resume Next
tBuffer = m_oReassembly(CStr(lSequence))
On Error GoTo 0
If tBuffer.TotalCount = 0 Then
' New sequence
Debug.Print "New sequence: " & lSequence
End If
' Store packet
tBuffer.Packets(lIndex) = sData
tBuffer.ReceivedCount = tBuffer.ReceivedCount + 1
' Update buffer
If tBuffer.ReceivedCount = tBuffer.TotalCount Then
' All packets received, reassemble data
Dim sComplete As String
Dim i As Long
For i = 0 To tBuffer.TotalCount - 1
sComplete = sComplete & tBuffer.Packets(i)
Next
Debug.Print "Sequence " & lSequence & " reassembly complete, total size: " & Len(sComplete)
' Process complete data
ProcessCompleteData sComplete
' Delete buffer
m_oReassembly.Remove CStr(lSequence)
Else
' Update buffer
m_oReassembly.Remove CStr(lSequence)
m_oReassembly.Add tBuffer, CStr(lSequence)
End If
End Sub🕐 Timeout Retransmission
' Timeout retransmission mechanism
Private Type tPendingPacket
Sequence As Long
Index As Long
Data As String
Timestamp As Double
RetryCount As Long
End Type
Private m_oPendingPackets As Collection
Private Const PACKET_TIMEOUT As Double = 5 ' 5 second timeout
Private Const MAX_RETRIES As Long = 3
' Send packet with timeout
Private Sub SendWithTimeout(ByVal lSeq As Long, ByVal lIdx As Long, ByVal sData As String)
' Send data
m_oUdp.SendData "PKT:" & lSeq & ":" & lIdx & ":" & sData
' Add to pending list
Dim tPending As tPendingPacket
tPending.Sequence = lSeq
tPending.Index = lIdx
tPending.Data = sData
tPending.Timestamp = Timer
tPending.RetryCount = 0
m_oPendingPackets.Add tPending, CStr(lSeq) & ":" & CStr(lIdx)
Debug.Print "Sent packet " & lSeq & ":" & lIdx & ", waiting for acknowledgment..."
End Sub
' Check timeout
Private Sub tmrTimeout_Timer()
Dim i As Long
For i = m_oPendingPackets.Count To 1 Step -1
Dim tPending As tPendingPacket
tPending = m_oPendingPackets(i)
' Check if timeout
If Timer - tPending.Timestamp > PACKET_TIMEOUT Then
If tPending.RetryCount < MAX_RETRIES Then
' Retransmit
Debug.Print "Packet " & tPending.Sequence & ":" & tPending.Index & " timeout, retrying..."
' Resend
m_oUdp.SendData "PKT:" & tPending.Sequence & ":" & tPending.Index & ":" & tPending.Data
' Update retry count and time
tPending.RetryCount = tPending.RetryCount + 1
tPending.Timestamp = Timer
m_oPendingPackets.Remove i
m_oPendingPackets.Add tPending, CStr(tPending.Sequence) & ":" & CStr(tPending.Index)
Else
' Max retries reached, give up
Debug.Print "Packet " & tPending.Sequence & ":" & tPending.Index & " exceeded max retries, giving up"
m_oPendingPackets.Remove i
End If
End If
Next
End Sub
' Acknowledge packet
Private Sub AckPacket(ByVal lSeq As Long, ByVal lIdx As Long)
Dim sKey As String
sKey = CStr(lSeq) & ":" & CStr(lIdx)
On Error Resume Next
m_oPendingPackets.Remove sKey
On Error GoTo 0
Debug.Print "Acknowledged packet " & lSeq & ":" & lIdx
End SubCommon Issues
❓ Issue 1: UDP Packet Loss
Symptom: Sent data not received by peer
Cause: UDP is unreliable transmission, packets may be lost
Solution: Implement acknowledgment and retransmission mechanism (as shown above)
❓ Issue 2: Packet Out of Order
Symptom: Received packets not in same order as sent
Cause: UDP doesn't guarantee ordering
Solution: Implement sequence number and reassembly mechanism
❓ Issue 3: Duplicate Packets
Symptom: Receiving duplicate packets
Cause: Caused by retransmission
Solution: Deduplicate by sequence number
Private Function IsDuplicate(ByVal lSequence As Long) As Boolean
Static lLastSequence As Long
If lSequence <= lLastSequence Then
IsDuplicate = True
Else
IsDuplicate = False
lLastSequence = lSequence
End If
End Function❓ Issue 4: Broadcast Failure
Symptom: No response after sending broadcast
Cause: Firewall blocking broadcast
Solution: Configure firewall or use specific port
' Try different broadcast addresses
m_oUdp.RemoteHost = "192.168.1.255" ' Subnet broadcast
m_oUdp.SendData "Broadcast"❓ Issue 5: Virtual Client Not Cleaned
Symptom: UDP server client list keeps growing
Cause: UDP connectionless, cannot automatically detect client disconnect
Solution: Implement timeout cleanup mechanism
Private Sub tmrCleanup_Timer()
Dim oClient As cWinsock
Dim tSession As tSessionData
For Each oClient In m_oUdpServer.Clients
tSession = oClient.UserData
' Check timeout
If DateDiff("s", tSession.LastActivity, Now) > 300 Then
Debug.Print "Clean up timeout client: " & oClient.Tag
oClient.Close_
End If
Next
End SubLast Updated: 2026-01-09