2
votes

I made a software couple years ago using VB6 that works as a TCP server, receives multiple connections from clients.

The basic Idea of the software is to listen on a specific port, accept connections from different clients and pass each connection to a separate winsock which analyzes the data, looks in DB, replies with the proper message, and then closes the connection.

Here's some code:

Initializing the sockets when the application starts:

For i = 1 To MaxCon    
    Load sckAccept(i)
Next i
sckListen.Listen

Accepting connections:

Private Sub sckListen_ConnectionRequest(ByVal requestID As Long)
    Dim aFreeSocket As Integer
    aFreeSocket = GetFreeSocket
    If aFreeSocket = 0 Then
        sckAccept(0).Accept requestID
        sckAccept(0).SendData "Server is full!"
        sckAccept(0).Close
    Else
        sckAccept(aFreeSocket).Accept requestID        
End Sub

Receiving data, analyzing it, and reply:

Private Sub sckAccept_DataArrival(Index As Integer, ByVal bytesTotal As Long)
    Dim sData As String  
    sckAccept(Index).GetData sData
    'Do lots of analyizing and search in DB
    '
    '
    sckAccept(Index).SendData "Message"
    '
    '
    DoEvents
    sckAccept(Index).Close
End Sub

Everything was working fine, but now the number of connections has increased (couple dozens per second), so the software started getting Out of stack space exception (because of DoEvents).

I know that in many cases DoEvents is evil, but if I remove it, the application UI won't respond (because of the over load on the thread) and some data might not be delivered.

So, my question is: does anyone have an idea of how to get around this problem with/without using DoEvents?


Note: I know that VB6 doesn't really support multi-threading and might be a PITA for such situations. I'm actually planning to upgrade the software and re-create it using .Net, but that will take some time. That's why I need to fix this problem in VB6 since the software is written in VB6 for now.

1
I honestly do not understand why should the doevents be in the last line of the dataarrival handler, i would have put it inside the heavy loop. Technically the doevents does a simple "yield", thus, the out of stack error might have another source like the size of sdata, i would place it in an array outside and access it using the connection index , i perfectly understand this is dirty, but should help save some heap.Gar
1- I put DoEvents inside the DataArrival handler because it triggers Winsock.SendData and "if I remove it, the application UI won't respond (because of the over load on the thread) and some data might not be delivered". 2- What do you mean with 'heavy load'? 3- When the Out of stack space error occurs, the stack is full of sckAccept_DataArrival events. I'm assuming this is because DoEvents allows the event to be triggered again (which contains another DoEvents, and so on). 4- The sData size is pretty small (40-100 bytes)41686d6564
i fully understand why you used the doevents, i just do not see it by the end of the sub, i use to "doevents" inside loops so that the loop do not lock the application. And even if the sdata is small you can only earn a few space putting it outside ans loose nothing. I understand as well that what causes your problem is a stacking of unanswered tcp queries (as their handler is querying the database for them).Gar
DoEvents() calls do far more than "yield" and any use of these at all in a program using controls raising external events (prime example being the Winsock control) is an error. If you have blocks of QBasic-style code that blocks event handling you need to rewrite them. There is no simple advice that is going to solve your problem, you need to have an experienced programmer take a look at it.Bob77

1 Answers

2
votes

Well, I managed to figure out the problem, and have solved it.

The short answer

Do NOT use DoEvents.. Some data won't be delivered? Well, close the connection ONLY in the SendComplete event.


The long answer

First thing first:

Why I used DoEvents in the first place? because some of the sent messages were not being delivered. A lot of articles/questions on the internet suggest using DoEvents after Socket.SendData in order to guarantee the data arrival to the receiver.

I digged deeper into this trying to figure out why the messages aren't delivered. I found out that this problem only occurs when closing the connection after sending the message:

Socket.SendData "Message"
'
'
Socket.Close

So, I simply moved the line that closes the connection to the SendComplete event, removed the DoEvents sentence -since I don't need it anymore-, and the problem is gone :)

Private Sub sckAccept_SendComplete(Index As Integer)
    sckAccept_Close (Index)
End Sub

I hope this could help someone who has the same problem.