Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Async VB6 socket TCP design question 1

Status
Not open for further replies.

BA2PC

Programmer
Oct 8, 2007
8
US
I am designing a VB app that needs Async TCP comm with custom Ethernet hardware units (256 max).

I would like to "fork" a child process for every TCP comm event from a specific IP address and socket and carry out the "state" and then close the process.

Could anyone recommend some further reading or highlight some issues?

 
Well to start with you have some foreign jargon in there.

"Fork" smells a bit *NIXie but I get your drift there.

"TCP comm event" doesn't seem to mean a thing to me. Is this a conection request?

"Carry out the 'state'" leaves me totally confused.

But one thing's for sure at least in my experience, you can't pass the [tt]requestId[/tt] from a connection request across processes.
 
dillettante,

Thanks for your response. I am probably mixing up nomenclature in my attempt to describe this in psuedo code.

I need to design a program that will handle bi-directional data on a TCP socket bound to a port. Many, many small pieces of data from different IP address. We have built these devices using a PIC ethernet controller so I have very low-level TCP control.

If I poll in my server application (VB), I am going to be massively inefficient. I am turning off the Nagle algorithm on TCP, but still. I am thinking that if I could spawn child preceesses for each unique port (or socket? or session) started by our hardware, I could simple launch this state machine, one per session and let it run to completion. The parent process would watch for exceptions.

Is that clearer? A well defined problem is half the solution.
 
Are you committed to doing this in VB6? C++ would seem to be a much better implementation choice.
 
avan,

C++ because of the thread handling? Unfortunately, I do not have C++ experience. How steep is the learning curve?
 
Thanks, that helps. Keep in mind it may just be me being dense on this end too.

Ok, you say TCP and you mention Nagle so you must really mean TCP and not UDP.

You mention "many small pieces of data" - can we assume these are arriving from reasonably persistent connections? Or do these custom devices connect, send, await reply, then disconnect? Scratch that. If you have to send a reply it doesn't really matter whether connections are held or re-established each time.


Ok, I'm starting over here. Hmm.

What makes you think you'd be doing any polling? The normal model for VB programming is an event-driven state machine already. You have to go through gyrations to poll anyway.

I'm not even sure what might be a challenge here for a VB program anyway. Unless you are doing some really significant level of processing every time one of these PIC-based devices sends you data, and these arrive very frequently, a VB program should handle hundreds if not thousands of the devices using just the standard Winsock control.

I've pushed a small TCP server written this way to a bit over 3000 simultaneous connections sending at 1 second intervals as a test before. The only action was an echo, but this was on an old 400Mhz Windows machine too.

You don't need any C++ here.

The VB program just needs a control array of Winsock controls. You use one control (which can be outside the array) to Bind & Listen for the incoming connection requests. Keep a parallel Boolean array to track "in use" state efficiently, and when you get a connection request scan the "in use" array for an available entry then Accept on that Winsock array element. If all are in use, Load another entry (or 10) and Redim the Boolean array up by the same number. As connections close, mark them not "in use." As a refinement, when you scan and find one not "in use" be sure to also check its State to make sure it is back to sckClosed - if not, scan for another available slot.

When data arrives you'll see an event raised. The index of the connection is passed to the handler as a parameter.

Note that you'll also need another array to buffer data arrivals that parallels the Winsock control array. You never have a guarantee that data will arrive in the same chunks as it was sent with TCP. Depending on the messaging protocol you use on top of TCP you can receive things "bunched together" even with the Nagle algorithm disabled

When both client and server are relatively slow and the network is relatively fast you will usually see:

Naive expectation:
[tt]Client Device VB Server
abc -->
--> abc
xyz -->
--> xyz
hello -->
--> hello[/tt]

This is great... until it fails.

Reality intrudes:
[tt]Client Device VB Server
abc -->
xyz -->
--> abcxyz ???
hello -->
--> h ???
--> ell ???
--> o ???[/tt]

Some people use chatty protocols to hope to mask this. Those tend to break mysteriously as well:

Naive expectation:
[tt]Client Device VB Server
abc -->
--> abc
<-- ACK!
ACK! <--
xyz -->
--> xyz
<-- ACK!
ACK! <--[/tt]

Reality intrudes:
[tt]Client Device VB Server
abc -->
--> ab ???
<-- ACK!
ACK! <--
xyz -->
--> cx ???
<-- ACK!
ACK! <--
--> yz ???
<-- ACK!
ACK! <-- ???[/tt]

The client can get totally lost. The server may dicard requests as junk or worse misinterpret them. People often throw in extra code to discard the extra ACKs when closing, but things can get ugly if the ACK contains important information or synchronization data. Unless the ACKs are a single octet (byte) you also risk them arriving fragmented as well.

So when data arrives for a connection you must get it and append it to a per-connection buffer. Then you parse the reassembled data for message framing, which is often as simple as an End Of Message symbol (CR, etc.) but may instead consist of a message length prefix. Process each intact message in the buffer (extracting them) and then exit awiting a new data arrival.

Alternatively one can PeekData the Winsock control's input queue on each data arrival until the desired contents are present. This can result in performance problems though, and generally you still have to deal with things like a whole message (or two, three, etc.) and a leftover piece of the next one to come.

But that's all standard stuff.


I really don't think you'll gain much from a bunch of child worker processes. Worse than that though, as I said you can't pass a requestID to another process. That effectively rules the option out.

Where C++ (or VB.Net, or C#, etc.) come in might be to use multiple threads. I think you already know that is generally more trouble than it is worth in VB 5&6.


Using a single process you do have to handle context management for each connection, sure. The easiest way to simplify that is to wrap a Winsock control and other context information (receive stream buffer, "in use" flag, misc. session state related to your application, etc.) into a UserControl. Then in the main Form use a control array of those instead and simply do the listening on another Winsock control and manage connection requests in the Form. You can write most of the UserControl's logic as if it were running in its own process anyway (i.e. no dealing with arrays and their indexes).

You may only need to expose an Accept method and an InUse property.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top