Valhalla Legends Archive

Programming => General Programming => Visual Basic Programming => Topic started by: vector on October 27, 2008, 10:42 PM

Title: Handling multiple sockets flawlessly?
Post by: vector on October 27, 2008, 10:42 PM
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)
Title: Re: Handling multiple sockets flawlessly?
Post by: Yegg on October 27, 2008, 11:47 PM
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.
Title: Re: Handling multiple sockets flawlessly?
Post by: Barabajagal on October 27, 2008, 11:56 PM
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.
Title: Re: Handling multiple sockets flawlessly?
Post by: vector on October 29, 2008, 05:13 PM
Thanks Andy. I wish IsObject() would return False if the particular array element wasn't loaded, but it returns true....
Title: Re: Handling multiple sockets flawlessly?
Post by: Barabajagal on October 29, 2008, 06:40 PM
Object arrays automatically load all the elements... I think?
Title: Re: Handling multiple sockets flawlessly?
Post by: Ringo on October 29, 2008, 06:46 PM
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)
Title: Re: Handling multiple sockets flawlessly?
Post by: Barabajagal on October 29, 2008, 07:39 PM
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...
Title: Re: Handling multiple sockets flawlessly?
Post by: l2k-Shadow on October 29, 2008, 07:49 PM

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
Title: Re: Handling multiple sockets flawlessly?
Post by: vector on November 03, 2008, 03:07 PM
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?
Title: Re: Handling multiple sockets flawlessly?
Post by: Barabajagal on November 03, 2008, 04:02 PM
Let's see your close error. And next time, run it from the IDE so you find out where the error is...
Title: Re: Handling multiple sockets flawlessly?
Post by: Ringo on November 03, 2008, 11:13 PM
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.
Title: Re: Handling multiple sockets flawlessly?
Post by: vector on November 04, 2008, 02:23 PM
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.
Title: Re: Handling multiple sockets flawlessly?
Post by: Barabajagal on November 04, 2008, 02:26 PM
...Why are you unloading the socket entirely like that? Are these actual Winsock objects?
Title: Re: Handling multiple sockets flawlessly?
Post by: vector on November 04, 2008, 05:57 PM
Yes. Well, it's a control array actually. I load the socket if its last socket in the array. Should I not unload it?
Title: Re: Handling multiple sockets flawlessly?
Post by: Barabajagal on November 04, 2008, 06:10 PM
I don't think Winsock likes dynamic arrays like that...
Title: Re: Handling multiple sockets flawlessly?
Post by: vector on November 05, 2008, 01:46 PM
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.
Title: Re: Handling multiple sockets flawlessly?
Post by: TheMinistered on November 20, 2008, 01:37 PM
search pscode.com for "david Fritts" you'll find really good sample project on how to do this