I'm trying to polish my server so it can handle multiple sockets flawlessly. Say three sockets are connected.
When socket 2 leaves, I want to be able to re-use socket 2. When 1 leaves, I want to re-use 1, etc.
I keep trying so and get problems. I've been trying again and again to handle sockets perfectly.
Please note that I'm using two sockets. A listening socket, and a control array.
Can you post an example of the proper way of handling sockets? (the Winsock_ConnectionRequest Sub is all I need)
Couldn't they all simply operate on their own thread? Store them in an array as you are already doing. If they are all on their own thread, you can have a function running within each thread that does whatever task whenever the socket loses its connection. Should be pretty simple.
Dim I As Integer
For I = 0 To 99
If Winsock(I).State = 0 Then
Winsock(I).Accept requestID
Exit For
End If
Next I
Just make sure to close the socket when disconnected.
Thanks Andy. I wish IsObject() would return False if the particular array element wasn't loaded, but it returns true....
Object arrays automatically load all the elements... I think?
Quote from: vector on October 29, 2008, 05:13 PM
I wish IsObject() would return False if the particular array element wasn't loaded, but it returns true....
Theres probly a few ways around that, but iirc, this will do the job:
IsLoaded = (VarType(Control(X))=vblong)
I know you can do If Not Ary() Then to detect if an array hasn't been initialized, but I don't think individual elements of arrays work like that...
Private Sub Form_Load()
Dim i As Integer
'Load Winsock1(1)
For i = 0 To 1
If IsLoaded(Winsock1(i)) Then MsgBox i & " Is Loaded!"
Next i
End Sub
Public Function IsLoaded(ByVal W As Winsock) As Boolean
If VarType(W) <> vbObject Then IsLoaded = True
End Function
enjoy
Interesting.
I took Andy's advice, and it looks nicely:
Private Sub sckListen_ConnectionRequest(ByVal requestID As Long)
Dim i As Integer
For i = 0 To sckRecv.Count
If i = sckRecv.Count Then
Load sckRecv(i)
sckRecv(i).Accept requestID
Exit Sub
Else
If sckRecv(i).State = sckClosed Then
sckRecv(i).Accept requestID
Exit Sub
End If
End If
Next
End Sub
But the wird thing is, when a client leaves, the sckRecv_Close() sub seems to be calling more than once, and the clients seem to be acting up.
(http://i52.photobucket.com/albums/g38/dj_dances/weird-1.jpg)
Quite strange.
Do you know anything about this?
Let's see your close error. And next time, run it from the IDE so you find out where the error is...
id persionaly do somthing like this (dunno if this helps you at all)
create module called modWinsock.bas
create a module called modClient.bas
create a class called clsClient.cls
modwinsock.bas would be used to managed an array of winsocks, across the whole project.
modclient.bas would be used to manage an array of client class's
clsclient.cls would be used to manage a clients connection and what not.
then in you're form code:
Public WithEvents sckServer As MSWinsockLib.Winsock
Private Sub Form_Load()
Dim i As Integer
modWinsock.hSocketCount = -1
modClient.hClientCount = -1
i = modWinsock.GetFreeSocket(Me)
Set sckServer = modWinsock.hSocket(i)
sckServer.Close
sckServer.Bind 2392, sckServer.LocalIP
sckServer.Listen
End Sub
Private Sub sckServer_ConnectionRequest(ByVal requestID As Long)
Dim i As Integer 'socket index
Dim i2 As Integer 'client index
i = modWinsock.GetFreeSocket(Me)
i2 = modClient.GetFreeClient()
modClient.hClient(i2).sckIndex = i
Set modClient.hClient(i2).sckRecv = modWinsock.hSocket(i)
Call modClient.hClient(i2).Accept(requestID)
End Sub
In the modClient.bas code:
Public hClient() As clsClient
Public hClientInUse() As Boolean
Public hClientCount As Integer
Public Function GetFreeClient() As Integer
Dim i As Integer
For i = 0 To hClientCount
If (hClientInUse(i) = False) Then
hClientInUse(i) = True
GetFreeClient = i
Exit Function
End If
Next i
hClientCount = hClientCount + 1
i = hClientCount
ReDim Preserve hClientInUse(i)
hClientInUse(i) = True
ReDim Preserve hClient(i)
Set hClient(i) = New clsClient
hClient(i).clsIndex = i
GetFreeClient = i
End Function
Public Sub ReleaseClient(ByVal i As Integer)
If (i < 0) Or (i > hClientCount) Then Exit Sub
Set hClient(i).sckRecv = Nothing
Call modWinsock.ReleaseWinsock(hClient.sckIndex)
hClient(i).sckIndex = -1
hClientInUse(i) = False
End Sub
in the modWinsock.bas code:
Public hSocket() As MSWinsockLib.Winsock
Public hSocketInUse() As Boolean
Public hSocketCount As Integer
Public Function GetFreeSocket(ByRef F As VB.Form) As Integer
Dim i As Integer
For i = 0 To hSocketCount
If (hSocketInUse(i) = False) Then
hSocketInUse(i) = True
GetFreeSocket = i
Exit Function
End If
Next i
hSocketCount = hSocketCount + 1
i = hSocketCount
ReDim Preserve hSocketInUse(i)
hSocketInUse(i) = True
ReDim Preserve hSocket(i)
Set hSocket(i) = F.Controls.Add("MSWinsock.Winsock", "Winsock" & i)
GetFreeSocket = i
End Function
Public Sub ReleaseSocket(ByVal i As Integer)
If (i < 0) Or (i > hSocketCount) Then Exit Sub
If hSocketInUse(i) Then
hSocketInUse(i) = False
hSocket(i).Close
End If
End Sub
and in the clsClient.cls code:
Public WithEvents sckRecv As MSWinsockLib.Winsock
Public clsIndex As Integer
Public sckIndex As Integer
Public Sub Accept(ByVal requestID As Integer)
sckRecv.Close
sckRecv.Accept requestID
End Sub
Private Sub sckRecv_Close()
Call modClient.ReleaseClient(clsIndex)
End Sub
Private Sub sckRecv_Error(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)
Call modClient.ReleaseClient(clsIndex)
End Sub
That way, you can manage many types of client's/class's, all from the same winsock array.
For example, you could have a clsFTP.cls client class, that could also get an avalible socket index, from the winsock array. 1 array of winsocks, multiple uses.
But thats just me :p
Dunno if that helps you, or puts an idea in your head or not.
In my sckRecv_Close() sub, I have a feeling that this piece of code:
If Index = sckRecv.Count Then Unload sckRecv(Index)
Was for some reason causing the program to re-call the Close() sub, then it happens again, and again.
...Why are you unloading the socket entirely like that? Are these actual Winsock objects?
Yes. Well, it's a control array actually. I load the socket if its last socket in the array. Should I not unload it?
I don't think Winsock likes dynamic arrays like that...
I feel like an idiot. On the client, when the form terminated, it would call sckSend.Close, and on the server side, when the socket quits, the close() sub was actually executing twice. I took that line from the client out, and it does just what its supposed to do normally.
search pscode.com for "david Fritts" you'll find really good sample project on how to do this