Simultaneous data handling (asyncStreams) problem

mc73

Well-Known Member
Licensed User
Longtime User
My app sends data to a server (also written in b4a) and I do this from 3-4 clients simultaneously.
Following a recommendation from Erel, I used AsyncStreams and for every client I have, I created a different Stream and Socket object at the server's side, by having an array of sockets (I am not sure if this was exactly what was proposed).
So, I have an array of 10 sockets, dimed as
B4X:
dim socket1(10) as socket
and a global array
B4X:
Dim socketsStatus(10) As Int
, indicating if the socket(L) is free or not. Then, when a connection is established, at the server's side, I use the following code, in order to choose a free socket for the new connection:
B4X:
Sub Server_NewConnection (Successful As Boolean, NewSocket As Socket)
    If Successful Then

                Dim freeSocketId As Int 
      freeSocketId=-1
      Dim k As Int 
      k=-1
      Do While freeSocketId=-1 AND k<9
      k=k+1
      If socketsStatus(k)=0 Then
      socketsStatus(k)=1:freeSocketId=k
      socket1(freeSocketId)=NewSocket
      fSocket=freeSocketId
      End If
      Loop
      
      If freeSocketId=-1 Then
      freeSocketId=0
      socket1(freeSocketId)=NewSocket
      fSocket=freeSocketId
      End If
      aStreams(freeSocketId).InitializePrefix(socket1(freeSocketId).InputStream, False, socket1(freeSocketId).OutputStream, "AStreams" & freeSocketId)

   Else
        ToastMessageShow(LastException.Message, True)
    End If
    server.Listen
   
End Sub

When I test it, sometimes it works well, sometimes not, thus making debugging hard. I suspect that the problem is that when I have a new connection established, at the very same moment with another connection established, the routine for giving the free socket ID is working for both at the same time, so that the routine doesn't have enough time to write
B4X:
socketsStatus(k)=1:freeSocketId=k
.
Then, I've tried stopping the connection routine, in order to avoid such conflict (if it really exists), by adding this line at the beginning of the connection routine:
B4X:
 Do While socketProccess=True:Log("I wait"):Loop
        socketProccess=True
I write socketProccess=true and then at the end of the routine, I set it to false, leaving the next connection to be established. It didn't work :(
Also, I've tried to place a doEvents inside this small loop. Again nothing.

Any ideas on what can be wrong here, or perhaps if the method I use is not neccessary? I mean, I still don't know whether I really have to have multiple sockets at the server's side. Thank you.
 

mc73

Well-Known Member
Licensed User
Longtime User
Silly me, It had nothing to do with socket counting. I had two mistakes in the client's side, a) I was using a buffer array again in a routine, which was wrong in this case, and b) I was sending a 'closeSocket' command from the client but without a 'end' string, so server counted a new socket and thus didn't close the correct 'finished' socket. :sign0148: Perhaps side-effect of the flu that got me. Please Consider thread closed, sorry...
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I suspect that the problem is that when I have a new connection established, at the very same moment with another connection established, the routine for giving the free socket ID is working for both at the same time, so that the routine doesn't have enough time to write
Note that your code runs in the main thread. This means that such a case cannot happen and you do not need to worry about it.
 
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
Note that your code runs in the main thread. This means that such a case cannot happen and you do not need to worry about it.

Thank you for your reply,Erel. Yes, this is what I've read, and since last night and the changes I made, so far, so good :)
Still, do I really need this socket&streams array? I'm puzzled here, because what if I need to have 100 devices connected at the same time? Should I have 100 sockets on the server side?
 
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
Thank you. At least now i can be more confident that i am on the right track. Is there any property of socket that can be read to inform us if it's a used on or i should stick with using a flag array?
 
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
You should probably use a Map with the client ids (not sure that it will be in your case) as the keys and the sockets as values. Then when a connection is closed you should remove the entry from the Map.
True. I have a 'terminal' id for every single device, but the reason I chose to use a simple flag array for sockets, with no info about ID attached to them, is that I couldn't figure out how to tell server the terminal's ID at the socket opening procedure, i.e. before I start the asynchronous streaming. This of course, is not very pleasent, since I would certainly prefer to have a single key for every machine, instead of a 'terminaID' and a 'openSocketID'. That's why I asked if socket has a property I didn't find so far, which could help.
 
Upvote 0
Top