cWinsock User Binding and Group Management
Feature Overview
User binding and group management features provide a complete user identity management and message distribution mechanism:
- User Binding: Associate user identity with socket connection, support sending messages by username
- Group Management: Group users for batch message sending and management operations
- Bidirectional Sync: Group operations automatically sync server-side and client-side
CurrentGroups - Auto Cleanup: Automatically unbind when user disconnects, no manual handling needed
Key Properties
| Property | Type | Description |
|---|---|---|
CurrentUser | Variant | Username bound to client instance |
CurrentUserToken | String | User token bound to client instance (e.g., auth token) |
CurrentUserInfo | cJson | User extended info bound to client instance (JSON object) |
CurrentGroups | Dictionary | Group list client belongs to (group name → True) |
User Binding
BindUser Method
Description
Binds a user to a client connection, achieving association between user identity and socket connection.
Syntax
Public Sub BindUser(ByVal User As Variant, Client As cWinsock, Optional ByVal Token As String, Optional Info As cJson)Parameters
| Parameter | Type | Description |
|---|---|---|
User | Variant | User identifier (string or other unique value) |
Client | cWinsock | Client socket instance |
Token | String (optional) | User auth token, can be retrieved via Client.CurrentUserToken after binding |
Info | cJson (optional) | User extended info (JSON object), can be retrieved via Client.CurrentUserInfo after binding |
Usage Example
' Server: Bind user when client connects
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
' Parse login message, format: "LOGIN:username"
If Left$(sData, 6) = "LOGIN:" Then
Dim sUsername As String
sUsername = Mid$(sData, 7)
' Bind user to client (with Token and extended info)
Dim oInfo As New cJson
oInfo.Add "loginTime", Now
oInfo.Add "ip", Client.RemoteHostIP
m_oServer.BindUser sUsername, Client, "secret_token_123", oInfo
Client.SendData "LOGIN:OK"
Debug.Print "User " & sUsername & " logged in, Token: " & Client.CurrentUserToken
End If
End SubExistsUser Method
Description
Check if specified user is bound.
Syntax
Public Function ExistsUser(ByVal User As Variant) As BooleanUsage Example
If m_oServer.ExistsUser("alice") Then
Debug.Print "User is online"
Else
Debug.Print "User is offline"
End IfUnbindUser Method
Description
Unbind specified user.
Syntax
Public Sub UnbindUser(ByVal User As Variant)Usage Example
' Manually kick user
If m_oServer.ExistsUser("alice") Then
m_oServer.UnbindUser "alice"
Debug.Print "User unbound"
End IfAuto Unbind
When user disconnects, system automatically removes from user list, no manual call needed.
SendToUser Method
Description
Send data to bound user.
Syntax
Public Sub SendToUser(ByVal User As Variant, Data As Variant, Optional ByVal CodePage As EnumScpCodePage = wcpAcp)Parameters
| Parameter | Type | Description |
|---|---|---|
User | Variant | User identifier |
Data | Variant | Data to send (string or byte array) |
CodePage | EnumScpCodePage (optional) | Text encoding, default wcpAcp |
Usage Example
' Send message to specific user
m_oServer.SendToUser "alice", "Hello, Alice!"
' Send with UTF-8 encoding
m_oServer.SendToUser "alice", "Hello, Alice!", wcpUtf8
' Broadcast message to all online users
Dim vUser As Variant
For Each vUser In m_oServer.m_Users.Keys
m_oServer.SendToUser vUser, "System announcement: Server maintenance in 5 minutes"
NextError Handling
If user doesn't exist, error is thrown:
On Error GoTo EH
m_oServer.SendToUser "bob", "Hello!"
Exit Sub
EH:
If Err.Number = vbObjectError Then
MsgBox "User is offline"
End IfGroup Management
Group management allows grouping users for easy batch message sending and management.
Prerequisites
Before binding to a group, user must first bind to client:
' ✅ Correct flow: Bind user first, then bind to group
m_oServer.BindUser "alice", Client
m_oServer.BindGroup "admins", Client
' ❌ Wrong: User not bound, cannot bind to group
m_oServer.BindGroup "admins", Client ' Will errorBindGroup Method
Description
Add client with bound user to specified group.
Syntax
Public Sub BindGroup(ByVal GroupName As String, Client As cWinsock)Parameters
| Parameter | Type | Description |
|---|---|---|
GroupName | String | Group name |
Client | cWinsock | Client instance with bound user |
Usage Example
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
' Parse join group request, format: "JOIN_GROUP:groupname"
If Left$(sData, 11) = "JOIN_GROUP:" Then
Dim sGroup As String
sGroup = Mid$(sData, 12)
' Check if user is bound
If LenB(CStr(Client.CurrentUser)) = 0 Then
Client.SendData "ERROR: Please login first"
Exit Sub
End If
' Join group
m_oServer.BindGroup sGroup, Client
Client.SendData "JOIN_GROUP:OK:" & sGroup
Debug.Print Client.CurrentUser & " joined group: " & sGroup
End If
End SubMultiple Joins to Same Group
Same user can call BindGroup multiple times for same group, but won't be added duplicate times.
ExistsGroup Method
Description
Check if specified group exists.
Syntax
Public Function ExistsGroup(ByVal GroupName As String) As BooleanUsage Example
If m_oServer.ExistsGroup("admins") Then
Debug.Print "Admin group exists, member count: " & m_oServer.GetGroupMembers("admins").Count
Else
Debug.Print "Admin group doesn't exist"
End IfUnbindGroup Method
Description
Remove user from specified group.
Syntax
Public Sub UnbindGroup(ByVal GroupName As String, ByVal User As Variant)Usage Example
' Remove user from group
m_oServer.UnbindGroup "admins", "alice"
' Group leader kicks user
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
If Left$(sData, 13) = "KICK_FROM_GROUP" Then
Dim sGroup As String, sTarget As String
sGroup = Mid$(sData, 14, InStr(sData, ":") - 14)
sTarget = Mid$(sData, InStr(sData, ":") + 1)
m_oServer.UnbindGroup sGroup, sTarget
Debug.Print sTarget & " removed from group: " & sGroup
End If
End SubAuto Cleanup
When all members leave a group, the group is automatically deleted.
GetGroupMembers Method
Description
Get list of all member usernames in specified group.
Syntax
Public Function GetGroupMembers(ByVal GroupName As String) As String()Return Value
Returns string array containing all member usernames. Returns empty array if group doesn't exist or is empty.
Usage Example
Dim aMembers() As String
Dim sMember As String
aMembers = m_oServer.GetGroupMembers("admins")
If UBound(aMembers) >= 0 Then
Debug.Print "Admin group has " & (UBound(aMembers) + 1) & " members:"
For Each sMember In aMembers
Debug.Print " - " & sMember
Next
Else
Debug.Print "Admin group is empty"
End IfSendToGroup Method
Description
Send data to all members in specified group.
Syntax
Public Sub SendToGroup(ByVal GroupName As String, Data As Variant, Optional ByVal CodePage As EnumScpCodePage = wcpAcp)Parameters
| Parameter | Type | Description |
|---|---|---|
GroupName | String | Group name |
Data | Variant | Data to send |
CodePage | EnumScpCodePage (optional) | Text encoding |
Usage Example
' Send group message
m_oServer.SendToGroup "developers", "Colleagues, tech sharing at 3pm today"
' Broadcast system announcement to all groups
Dim sGroup As Variant
For Each sGroup In m_oServer.m_Groups.Keys
m_oServer.SendToGroup CStr(sGroup), "[System] Server will restart in 10 minutes"
NextSmart Handling
- If group doesn't exist, no data is sent
- If some users in group are offline, they're automatically skipped, only online users receive
GetUserGroups Method
Description
Get list of all groups that specified user belongs to.
Syntax
Public Function GetUserGroups(ByVal User As Variant) As String()Return Value
Returns string array containing all group names.
Usage Example
' View groups user belongs to
Dim aGroups() As String
Dim sGroup As String
aGroups = m_oServer.GetUserGroups("alice")
If UBound(aGroups) >= 0 Then
Debug.Print "alice belongs to the following groups:"
For Each sGroup In aGroups
Debug.Print " - " & sGroup
Next
Else
Debug.Print "alice is not in any groups"
End IfDeleteGroup Method
Description
Disband specified group, synchronously deletes the group from all members' CurrentGroups.
Syntax
Public Sub DeleteGroup(ByVal GroupName As String)Usage Example
' Disband group
m_oServer.DeleteGroup "temp_group"
Debug.Print "Group disbanded"
' Admin disbands group
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
If Left$(sData, 12) = "DELETE_GROUP" Then
Dim sGroup As String
sGroup = Mid$(sData, 14)
If m_oServer.ExistsGroup(sGroup) Then
m_oServer.DeleteGroup sGroup
Debug.Print "Group " & sGroup & " has been disbanded"
End If
End If
End SubSync Mechanism
When disbanding a group, system automatically iterates all group members, removing the group name from each member's CurrentGroups.
CloseUser Method
Description
Force specified user offline, close their client connection.
Syntax
Public Sub CloseUser(ByVal User As Variant)Usage Example
' Kick specified user offline
m_oServer.CloseUser "alice"
Debug.Print "User offline"
' Admin kicks user
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
If Left$(sData, 5) = "KICK:" Then
Dim sTarget As String
sTarget = Mid$(sData, 6)
If m_oServer.ExistsUser(sTarget) Then
m_oServer.CloseUser sTarget
Debug.Print sTarget & " has been kicked by admin"
End If
End If
End SubCleanup Flow
Calling CloseUser triggers client's Class_Terminate, automatically completing the following cleanup:
- Unbind from all groups
- Remove from user list
- Clear
CurrentGroups
Internal Methods
The following methods are for internal use, usually don't need to be called directly:
UnbindUserFromAllGroups
Unbind user from all groups (called by Class_Terminate, automatically triggered when user disconnects). Syncs client CurrentGroups.
Data Structure and Sync Mechanism
Server-side Storage Structure
m_Users (Dictionary)
└── Username → cWinsock client instance
m_Groups (Dictionary)
└── Group name → Dictionary(Username → True)Client Instance Properties
CurrentUser (Variant)
└── Bound username
CurrentUserToken (String)
└── User auth token (Token passed when BindUser)
CurrentUserInfo (cJson)
└── User extended info (Info passed when BindUser)
CurrentGroups (Dictionary)
└── Group name → TrueBidirectional Sync
All group operations automatically sync server-side and client-side data:
| Operation | Server-side | Client-side |
|---|---|---|
BindGroup | Add to m_Groups[groupName] | Add to CurrentGroups |
UnbindGroup | Remove from m_Groups[groupName] | Remove from CurrentGroups |
DeleteGroup | Delete m_Groups[groupName] | Remove from all members' CurrentGroups |
UnbindUserFromAllGroups | Remove user from all groups | Clear CurrentGroups |
Auto Cleanup Mechanism
Cleanup Flow When User Disconnects
When client disconnects, system automatically executes the following cleanup:
1. Client Close_() or Class_Terminate() is called
2. Check if CurrentUser is empty
3. If not empty:
a. Call UnbindUserFromAllGroups() to remove from all groups
b. Call UnbindUser() to remove from user list
c. Clear CurrentGroups
d. Clear CurrentUser
e. Clear CurrentUserToken (set to empty string)
f. Clear CurrentUserInfo (call Clear)Memory Management Notes
User binding uses Dictionary to store user and group references. To avoid memory leaks:
- Always bind/unbind through server object: Don't directly operate internal
m_Usersandm_Groups - Use RemoveClient: Should call server's
RemoveClientmethod when client disconnects - Avoid circular references: Server holds client reference, client holds parent server reference (via
ParentServer)
Complete Chat Server Example
' Complete server-side example
Dim WithEvents m_oServer As cWinsock
Private Sub Form_Load()
Set m_oServer = New cWinsock
m_oServer.Protocol = sckTCPProtocol
m_oServer.Listen 8080
End Sub
' Handle connection request
Private Sub m_oServer_ConnectionRequest(Client As cWinsock, ByRef DisConnect As Boolean)
Debug.Print "New connection: " & Client.RemoteHostIP
End Sub
' Handle data arrival
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Client.GetData sData
' Parse command
Select Case Left$(sData, InStr(sData, ":") - 1)
Case "LOGIN"
HandleLogin Client, Mid$(sData, 7)
Case "JOIN_GROUP"
HandleJoinGroup Client, Mid$(sData, 12)
Case "MSG"
HandleMessage Client, Mid$(sData, 5)
Case "BROADCAST"
HandleBroadcast Client, Mid$(sData, 11)
End Select
End Sub
Private Sub HandleLogin(Client As cWinsock, ByVal sUsername As String)
If m_oServer.ExistsUser(sUsername) Then
Client.SendData "LOGIN:ERROR:User already logged in"
Exit Sub
End If
' Bind user, with Token and extended info
Dim oInfo As New cJson
oInfo.Add "loginTime", Now
oInfo.Add "ip", Client.RemoteHostIP
m_oServer.BindUser sUsername, Client, "secret_token_123", oInfo
Client.SendData "LOGIN:OK"
Debug.Print sUsername & " logged in, Token: " & Client.CurrentUserToken
End Sub
Private Sub HandleJoinGroup(Client As cWinsock, ByVal sGroup As String)
If LenB(CStr(Client.CurrentUser)) = 0 Then
Client.SendData "ERROR:Please login first"
Exit Sub
End If
m_oServer.BindGroup sGroup, Client
Client.SendData "JOIN_GROUP:OK:" & sGroup
Debug.Print Client.CurrentUser & " joined group: " & sGroup
End Sub
Private Sub HandleMessage(Client As cWinsock, ByVal sMsg As String)
If LenB(CStr(Client.CurrentUser)) = 0 Then
Client.SendData "ERROR:Please login first"
Exit Sub
End If
' Send message to all group members
m_oServer.SendToGroup "general", Client.CurrentUser & ": " & sMsg
End Sub
Private Sub HandleBroadcast(Client As cWinsock, ByVal sMsg As String)
If LenB(CStr(Client.CurrentUser)) = 0 Then
Client.SendData "ERROR:Please login first"
Exit Sub
End If
' Broadcast to all groups
Dim sGroup As Variant
For Each sGroup In m_oServer.m_Groups.Keys
m_oServer.SendToGroup CStr(sGroup), "[Broadcast] " & Client.CurrentUser & ": " & sMsg
Next
End Sub
' Handle client disconnect
Private Sub m_oServer_CloseEvent(Client As cWinsock)
If LenB(CStr(Client.CurrentUser)) <> 0 Then
Debug.Print Client.CurrentUser & " is offline"
' No need to manually unbind, system handles automatically
End If
End SubLast Updated: 2026-04-26