?
Solved

Synchronous Winsock?

Posted on 2010-01-05
14
Medium Priority
?
1,166 Views
Last Modified: 2013-11-13

Although my profile says I'm an expert, I'm really not (not sure how I received that classification).  I'm pretty much a newbie, having done some VB6 GPIB programming several years back.  So, I'm learning, or re-learning what I've done before.

I have a need to send queries to a spectrum analyzer, and to receive responses back using TCIP and winsock.  I've been somewhat successful, however occassionaly my little program hiccups, and because of the asynchronous nature of winsock, some of the returns are either overwritten or simply missed.  That may be due to analyzer task overload or LAN congestion.  The sequence goes something like this:

(-> indicates query from client to analyzer)
(<- indicates analyzer response to client)

What is the frequency? ->
<- The frequency is 1.12 GHz
What is the resolution bandwidth? ->
<- The resolution bandwidth is 100 kHz
What is the sweep? ->
<- The sweep is 893 ms

... and so on.


The issue is that I need to wait until I get a response from the analyzer before I send the next query.  Otherwise the response data is overwritten or somehow missed.  I have instituted a timing wait, but that seems somewhat clumbsy and if I create too long of a wait, the whole communication process just takes longer to complete.

So, my question is; is there a way to send a query, and as soon as the response is received, immediately send the next query?  I didn't seem to find anything in winsock that would permit that.  It seems that winsock was built to be asynchronous.
0
Comment
Question by:sherrele
  • 6
  • 5
  • 3
14 Comments
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26186409
Without seeing any code...

In the DataArrival() Event you get your response right?...after receiving a response you just send out the next request at the bottom of that event.

You'll have to keep track of what "step" you are in the communication process...a simple counter could work.
0
 
LVL 7

Expert Comment

by:js-profi
ID: 26188806
winsock itself is synchronous. it is the API and event handling around what makes it asynchronous. so indeed you have to wait for the response before sending the next request. idle_mind made a suggestion. you also could set a global flag when the response has arrived and check the flag using a periodic timer. that is when the receiving function has not enough info for sending the next request.
0
 

Author Comment

by:sherrele
ID: 26192935
Idle_Mind made a point there that I'm going to try.  My program was modeled after a chat example and as such the GetData statement is in a sub of its own (see Code A).  That's most likely because they want a chat to be asynchronous (duh).

So I assume that if I include the code "sock1.GetData strData, vbString" within the same sub that my "btnSingleTrace_Click()" (see Code B) is located, then it should work?  (The code shown has been reduced to just two of the dozen or more commands that need to be sent to the instrument)

I'll give that a try.
Code A:
Public Sub sock1_DataArrival(ByVal bytesTotal As Long)
    sock1.GetData strData, vbString 
End Sub

Code B:
Public Sub btnSingleTrace_Click()

    sock1.RemoteHost = strIP
    sock1.RemotePort = strPort

    sock1.Connect strIP, strPort

    ' Retrieve the center frequency from the instrument.
    txtCommand = Chr$(2) & ":Frequency:Center?" & Chr$(3)
    sock1.SendData txtCommand
 
    sock1.GetData strData, vbString 
    strFrequency = strData

    ' Retrieve the reference level information from the instrument.
    txtStatus = Chr$(2) & ":Display:Amplitude:RLevel?" & Chr$(3)
    sock1.SendData txtStatus

    sock1.GetData strData, vbString 
    strRefLevel = strData

End Sub

Open in new window

0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 

Author Comment

by:sherrele
ID: 26192980
Sorry.  The last two commands in the code have typos in them.  "txtStatus" should be replaced with "txtCommand".
0
 
LVL 7

Expert Comment

by:js-profi
ID: 26193038
you can't call sock1.GetData synchronously as it would retrieve nothing. the first sub is a callback which was called asynchronously when data had yet received. Put the sending of the second data to the first sub.
0
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 2000 total points
ID: 26193407
Totally untested as I don't have VB6 on my machines anymore!...   =\

See if you can follow this code:
    Public StepNumber As Long
    Public strFrequency As String
    Public strRefLevel As String

    Public Sub btnSingleTrace_Click()
        btnSingleTrace.Enabled = False
        StepNumber = 1

        sock1.RemoteHost = strIP
        sock1.RemotePort = strPort
        sock1.Connect(strIP, strPort)
        ' Once connected, the Connect() event below will fire...
    End Sub

    Public Sub sock1_Connect()
        ' Retrieve the center frequency from the instrument.
        txtCommand = Chr$(2) & ":Frequency:Center?" & Chr$(3)
        sock1.SendData(txtCommand)
        ' when a response comes back, the DataArrival event below will fire...
    End Sub

    Public Sub sock1_DataArrival(ByVal bytesTotal As Long)
        Select Case StepNumber
            Case 1
                sock1.GetData(strData, vbString)
                strFrequency = strData

                ' Retrieve the reference level information from the instrument.
                txtStatus = Chr$(2) & ":Display:Amplitude:RLevel?" & Chr$(3)
                sock1.SendData(txtStatus)

            Case 2
                sock1.GetData(strData, vbString)
                strRefLevel = strData

                MsgBox("Done!")
                btnSingleTrace.Enabled = True

        End Select
        StepNumber = StepNumber + 1
    End Sub

Open in new window

0
 

Author Comment

by:sherrele
ID: 26193707
Idle_Mind,
I'm going to try your suggestion when I have some time later today.

js-profi,
I don't quite understand.   The sending of commands requesting data from the instrument is initiated by a button click.  How do I incorporate a button click into the data arrival sub?

0
 
LVL 7

Expert Comment

by:js-profi
ID: 26196280
it was your requirement that the second query should occur after data from first query arrived. if that is still true the second query would not be triggered by button click but by the arrival of data.
0
 

Author Closing Comment

by:sherrele
ID: 31673249
Idle_Mind,

This works well.  I had some problems with the fact that my VB6 didn't like some of the parenthesis, but that was easy to figure out.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26205574
Ha...sorry about that.  I was using my VB.Net 2008 IDE to write that and .Net puts parenthesis on all calls...

Glad you figured it out!  =)
0
 

Author Comment

by:sherrele
ID: 26211759
Hi Idle_Mind,

Don't know if this is kosher (should this be another separate question?), but I am going to be querying a total of 5 spectrum analyzers using the code you supplied above.  Your code has been working great for a single analyzer.  However for the multiple analyzer task, this really needs to be in a subroutine that can be called as necessary.  So my question is, how would you make your code into a stand alone subroutine?

0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26211786
Depends...are you going to use a separate Winsock control for each analyzer?
...or are you going to use a Winsock Control Array?
0
 

Author Comment

by:sherrele
ID: 26212152
Well, I plan on creating a simple CSV configuration file that would hold the IP addresses of the various analyzers, as well as some of the parameter settings for each analyzer.  My program would read that file and then sequentially send out a group of queries to each analyzer one by one.  It would then save the returned data in a pre-determined folder selected by a combobox.  So it would go like this:

1. a. Send queries to analyzer one (frequency, span, etc.).
    b. Receive data into the various variables (frequency, span, etc.).
    c. Save the variables in a CSV file that is named based on analyzer IP address, date & time.
2. a. Send queries to analyzer two (frequency, span, etc.).
    b. Receive data into the various variables (frequency, span, etc.).
    c. Save the variables in a CSV file that is named based on analyzer IP address, date & time.
3. a. Send queries to analyzer three (frequency, span, etc.).
    b. Receive data into the various variables (frequency, span, etc.).
    c. Save the variables in a CSV file that is named based on analyzer IP address, date & time.

... and so on.  Each numbered step above would be a call to the subroutine consisting of your code.

The naming and saving of the CSV file to be saved is already working using your code.  I can do all this manually right now by selecting a different IP address in a combobox and clicking on the "SingleTrace" button, but obviously I wanted to automate it more.

0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26212322
Hmmm...the single threaded nature of VB6 makes this a pain in the butt...

One possibility is to toggle a boolean flag when the last value has been received from the analyzer.  Then you could poll from a loop looking for it.

Something ROUGHLY like:
    Public StepNumber As Long
    Public strFrequency As String
    Public strRefLevel As String
    Public Finished As Boolean

    Public Sub btnSingleTrace_Click()
        btnSingleTrace.Enabled = False

        ' pseudo code for the loop!
        For Each Analyzer In CSV_File
            QueryAnalzyer Analyzer.IP, Analyzer.Port
            While Not Finished
                DoEvents
            End While

            ' do something with strFrequency, strRefLevel, etc...

        Next

        btnSingleTrace.Enabled = True
        MsgBox "Done!"
    End Sub

    Public Sub QueryAnalzyer(ByVal strIP As String, ByVal strPort As String)
        StepNumber = 1
        Finished = False
        sock1.RemoteHost = strIP
        sock1.RemotePort = strPort
        sock1.Connect strIP, strPort
    End Sub

    Public Sub sock1_Connect()
        ' Retrieve the center frequency from the instrument.
        txtCommand = Chr$(2) & ":Frequency:Center?" & Chr$(3)
        sock1.SendData txtCommand
        ' when a response comes back, the DataArrival event below will fire...
    End Sub

    Public Sub sock1_DataArrival(ByVal bytesTotal As Long)
        Select Case StepNumber
            Case 1
                sock1.GetData strData, vbString
                strFrequency = strData

                ' Retrieve the reference level information from the instrument.
                txtStatus = Chr$(2) & ":Display:Amplitude:RLevel?" & Chr$(3)
                sock1.SendData txtStatus

            Case 2
                sock1.GetData strData, vbString
                strRefLevel = strData

                ' after the last "step", close the connection and toggle "Finished"
                sock1.Close
                Finished = True

        End Select
        StepNumber = StepNumber + 1
    End Sub

Open in new window

0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

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.
Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
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 …
Suggested Courses
Course of the Month13 days, 12 hours left to enroll

755 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