?
Solved

WinSock data loss?

Posted on 2003-03-24
17
Medium Priority
?
383 Views
Last Modified: 2013-11-13
Hi,

I have this WatchDog app that is connected to several servers. Each app runs as winsock server, while the watchdog is connected to them as client.
The client tells each app each <x> seconds to send status info back. I have a sockclient_dataArrival(index As Integer, ByVal bytestotal As Long) that is fired when the server reports data back to the client. So almost simultaneously this proc is fired when all servers report back their status.
I have the distinct feeling that not all data is processed. Is this a known behaviour of winsock? I mean, I expect each winsock client to hold on to the data until the VB app gets to it to process it. Is this correct?

Thanks,
  Simon
0
Comment
Question by:shvanwijlen
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 5
  • 3
  • +1
17 Comments
 
LVL 9

Expert Comment

by:GivenRandy
ID: 8194525
From my experience, all data is received. Are you using it as TCP or UDP?
0
 

Author Comment

by:shvanwijlen
ID: 8194975
TCP
0
 
LVL 9

Expert Comment

by:GivenRandy
ID: 8195639
Can you create different sockets for each watchdog client? That way you can spot each data arrival separately and confirm your suspicions.
0
Optimize your web performance

What's in the eBook?
- Full list of reasons for poor performance
- Ultimate measures to speed things up
- Primary web monitoring types
- KPIs you should be monitoring in order to increase your ROI

 
LVL 3

Expert Comment

by:y2ksw
ID: 8195713
If you have many clients, more than 5, you might need to use separate winsock controls, because the backlog of each socket is by default 5. That means a single socket in listen state cannot remember more than 5 requests at a time. If there are 4 pending requests, and one executing, all further requests are ignored. A good practice is to redirect a request to another socket (array of winsock controls) and keep the main socket listening only. If this doesn't solve the problem, you might opt for the API, which allows to set the backlog depth as needed. As far as I know, you may set up to 255 backlog levels for each socket. Note that you may not have more than 32768 sockets open at one time, and that eack backlog level counts as if it was a used socket.

Hope this helped.
0
 

Author Comment

by:shvanwijlen
ID: 8202633
The app has on the form 1 winsock control with index=0. I have 7 servers to connect to. On the server the control is in server mode; my app functions as a client to those 7 servers.
For each server (0..6) I load a new control except for the 1st one (index=0). So each "connection" has it's own control in the array of controls.

When I'm using the controls as clients, then I don't need the "main socket listening", right?

I have 1 routine sockClient_DataArrival(Index As Integer, ByVal bytesTotal As Long) with Index referencing in the array of controls. Since in a loop the app sends to all controls in this array the command "STATUS", they all at approx the same time send back the results. So this data-arrival routine is fired for a number of controls. While it is processing one control, the other's data will be buffered and dealt with, right? I'm afraid that because there are 7, the data returned, although less than 20 chars per control, is too much for the app to deal with.

If I were to go for the API - can you give me some hints on how to get documentation / examples for this?
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 8202746
>>If I were to go for the API - can you give me some hints on how to get documentation / examples for this?<<

I'd start at http://www.vbip.com/winsock-api/default.asp

You will find a number of articles with documentation.
0
 
LVL 3

Accepted Solution

by:
y2ksw earned 200 total points
ID: 8203229
Yes, that's a good site, more directly:

http://www.vbip.com/winsock-api/csocket-class/CSocket-1.0.12.zip

In this class you find all necessary calls and many examples for using the winsock API.

But: only use them if your problem cannot be solved with the OCX. API programming requires more skills and maintaining the code is not so easy as with the ready-to-use winsock control.

BTW, if you keep the sockets connected all the time, timeouts may happen depending on the system settings. The best way, really, is to make short requests, answer, and shut down. Keeping connections open require a lot of resources and useless data exchange (keep-alive) between the sockets.
0
 

Author Comment

by:shvanwijlen
ID: 8208957
For now, I've fixed it by decreasing my timer frequency to send the STATUS request to the connected apps from 1 to 5 sec, and to put a wait in the loop after each socket senddata. But I don't feel 100% comfortable. For now it's too much work to rewite the app although I'm thinking to follow y2ksw's advice to not keep the sockets open.
Thanks to y2ksw and the others for taking the time!

Regards,
  Simon
0
 

Author Comment

by:shvanwijlen
ID: 8209373
y2ksw & others - By adding a wait of 1 sec (using the MS solution of the timer value, and looing while DoEvents until timer+waitseconds have expired), I found that this pushes the CPU to 100%. Normally I don't have this since I use this wait method in other projects without problems. I don't understand why it is a problem in this loop (for i=0 to 7, do a senddata on each control, wait 1 sec, and to to the next).

But I feel the real problem is that when I do this for-next senddata on each control, the data does not arrive on the clients except one client. So I can't rely on the winsock control to deliver the info. I'm thinking of going for your open/close tip. But then my question is : I open the connection, send the "STATUS" command, and then close. But how can then the server send me back the results since the connection is closed. Or do I really have to close, and let the server setup a "one-time" connection to my server control to pass the results back? Is that not a lot of overhead too?

Thanks again,
 Simon
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 8210378
> open the connection, send the "STATUS" command, and then close.

No, wait for the result on that command.  Otherwise you have no guarantee that you will receive it.
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 8210437
By the way, I've written a program similar to this using the winsock control in an array, that's why I was lurking following the discussion.  My experience is the same as GivenRandy's, that you can use the winsock control in an array with no loss of data.

>>By adding a wait of 1 sec (using the MS solution of the timer value, and looing while DoEvents until timer+waitseconds have expired), I found that this pushes the CPU to 100%.<<

This almost sounds like you are using a polling model for this project.  I started that way with mine, but abandoned that model as unreliable.  My advice is to use a fully event driven model with no polling loops and your results will be much better.

0
 

Author Comment

by:shvanwijlen
ID: 8211663
I guess I use both. Using a timer I send a STATUS command to all servers attached. For each server I have a control in the array. For i=0 to maxservers sockserver(i).senddata "STATUS" next i

The server's implementation is event-driven : when data arrives on his server control, and when being the STATUS command, he returns on that same "connection" the results.

This then triggers the DataArrival event for that control on the watchdog which deals with the results returned by the server.

What is baffling me is that when I do this timer-based for-next, and send a "STATUS" on each separate control, the receiving app does not get it. But if I use a 2nd debug app to setup another connection between the same watchdog machine and that same other machine, and send this command manually, it does arrive. Even when the app with the for-next loop is also running and gets no results.
However if I put a 1-sec wait in that for-nect loop, the STATUS command does arrive...
0
 

Author Comment

by:shvanwijlen
ID: 8211687
Sorry Paul, in describing my problem I forgot to mention my questions :
- After doing the senddata, how do I wait for the results?
- You abandoned the polling model. Do you mean that your "watchdog" waits until the connected servers send the data? So they would have a timer to ensure you get results at least say every <x> minutes?
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 8212535
-- After doing the senddata, how do I wait for the results?

You don't do anything.  Your code flow starts with the timer driven query, then when the dataarrival fires the result is processed.  You use a state flag to indicate what step the timer code should be doing next.

-- You abandoned the polling model. Do you mean that your "watchdog" waits until the connected servers send the data? So they would have a timer to ensure you get results at least say every <x> minutes?

What I mean is there is no loop driven polling.  A timer initiates the query, the state is maintained in a variable so when the state is 'waiting reply' the timer skips over, eg.  (super simplified with only one winsock.  You could use an array of state variables.  Also notice I was lazy with the state variable.  A constant or enum would be more appropriate.)  Notice the different conditions to determine if the different states are complete in the data arrival.  You don't need to use the length to determine this, but you should have some clear cut termination of incoming data.

Option Explicit
Private mstrState As String
Private mstrData As String

Private Sub Form_Load()
    mstrState = "Status"
    Timer1.Interval = 500
    Timer1.Enabled = True
    Winsock1.RemoteHost = txtIP.Text
    Winsock1.RemotePort = txtPort.Text
End Sub

Private Sub Timer1_Timer()
    Select Case mstrState
    Case "Status"
        Winsock1.Close
        Winsock1.Connect
        Winsock1.SendData "STATUS"
    Case "Query"
        Winsock1.Close
        Winsock1.Connect
        Winsock1.SendData "QUERY"
    Case "Process"
        Call sProcessData
    Case "Waiting"
   
    End Select
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    Dim vData
    vData = Winsock1.GetData
   
    mstrData = mstrData & vData
    'Assumes different conditions for determining if status command or query command is completed
   
    Select Case mstrState
   
    Case "Status"
        'Check to see if all data received
        If Len(mstrData) = 10 Then
            mstrState = "Process"
        End If
   
    Case "Query"
        'Check to see if all data received
        If Len(mstrData) = 12 Then
            mstrState = "Process"
        End If
    End Select
End Sub

0
 
LVL 38

Expert Comment

by:PaulHews
ID: 8212542
Ooops missed something important:

Private Sub Timer1_Timer()
    Select Case mstrState
    Case "Status"
        Winsock1.Close
        Winsock1.Connect
        Winsock1.SendData "STATUS"
        mstrState = "Waiting"
    Case "Query"
        Winsock1.Close
        Winsock1.Connect
        Winsock1.SendData "QUERY"
        mstrState = "Waiting"
    Case "Process"
        Call sProcessData
    Case "Waiting"
   
    End Select
End Sub
0
 

Author Comment

by:shvanwijlen
ID: 8252517
I've reversed things. The central watchdog app is now 100% event driven. It has a list of apps he expects data from, so on the screen he can show the traffic lights for each app, but he only reacts to a data_arrival event from these apps. The apps send data timer-based as well as event-based (eg when something goes wrong). If the watchdog hasn't heard from an app withion <x> seconds he assume some thing is wrong -> traffic light goes red, emails are sent etc.

No data loss anymore. no CPU problems anymore.
0
 
LVL 3

Expert Comment

by:y2ksw
ID: 8254260
:-))
0

Featured Post

Optimize your web performance

What's in the eBook?
- Full list of reasons for poor performance
- Ultimate measures to speed things up
- Primary web monitoring types
- KPIs you should be monitoring in order to increase your ROI

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Suggested Courses

800 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question