?
Solved

TCP/IP with Winsock Control and VB 6

Posted on 2003-03-22
19
Medium Priority
?
1,418 Views
Last Modified: 2013-11-13
Hi.

I am using VB 6 with Winsock Control to build a TCP/IP based client. The server is NOT written by me and I don't have access to its source code, therefore I can't change the server in any way.

The client connects to the server through TCP/IP and then sends some commands for the server. The problem is that the server is built with the assumption that each TCP/IP packet would contain only ONE command therefore no delimiter is used for separating commands. Now when my client application sends multiple commands by calling SendData() method of Winsock control for each command, the Winsock combines those small packets with commands into a larger packet and then sends it. Winsock uses "Nagle algorithm for send coalescing", as mentioned in MSDN.

When this packet with multiple commands is received by the server, it is not accepted by it because now it has more than one command in a packet therefore it's not according to its format.

Therefore, what I need, is a way to “flush” the data before calling the SendData() method again so that new command is not concatenated with the previous ones.

From MSDN I came to know about a Winsock option "TCP_NODELAY", which does this, but it does not seem to work for me. Although I set this option but the behavior of the Winsock remained the same (I used sniffer to examine the packets). I also came to know that SDK for Win CE contained a bug which caused Winsock to ignore this option value. But I didn't find any article which indicated that this bug also exists in Win 9x/2000/XP.

I think an example would clear what I want to do.

Example
----------

I want to send some text/commands on TCP connection. They should be send in a way such that each packet contain only one command:

    Packet 1 -->    Command_1
    Packet 2 -->    Command_2
    Packet 3 -->    Command_3

But when I send the data using SendData() method of Winsock control:

    Wsk.SendData("Command_1")
    Wsk.SendData("Command_2")
    Wsk.SendData("Command_3")

Winsock combines all three commands in a single packet as :

    Packet 1 -->    Command_1Command_2Command_3

While I want winsock to send each command in a different TCP packet. That is, I want to packetize the TCP stream. I tried to enter some delay between SendData() calls but many times it also results in the concatenation of the commands. Besides this, I read in one article that the routers or destination end-point may combine the packets.

I would highly appreciate if you can help me.

Regards.
0
Comment
Question by:jazzzz20
[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
  • 9
  • 4
  • 2
  • +2
19 Comments
 
LVL 1

Expert Comment

by:leavinmate
ID: 8187593
How about adding one of the ASCII control characters to the end of the string?  Either a

EOT::=character_nbr(4)::= End Of Transmission(ASCII'EOT).

Or,

CR::=character_nbr(13)::= Carriage Return to left margin(ASCII'CR)\r.

I would add call with this line:
   Wsk.Sendata ("Command_1" & Chr$(4))

to Try it.

Another thing to try is to add a few DoEvents lines after each call.  However, this may cause issues if you're logic depends on all three calls to finish before moving on.

   Wsk.SendData("Command_1")
   DoEvents
   Wsk.SendData("Command_2")
   DoEvents
   Wsk.SendData("Command_3")
   DoEvents


FYI:
A full list of Control Characters can be found here:

http://www.csci.csusb.edu/dick/samples/comp.text.ASCII.html#Control%20characters
0
 
LVL 1

Expert Comment

by:leavinmate
ID: 8187608
Oh and another good control character to try might be the NUL  (Chr$(0))  

This is the string delimiter in windows and might work as well.
0
 

Expert Comment

by:MrDark
ID: 8187717
why don't you try to close the connection and connect.
try it it may work. The code will be:

wsk.Connect
wsk.SendData ("Command_1")
wsk.Close
wsk.Connect
wsk.SendData ("Command_2")
wsk.Close
wsk.Connect
wsk.SendData ("Command_3")
wsk.Close
wsk.Connect
wsk.SendData ("Command_4")
wsk.Close
wsk.Connect
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Author Comment

by:jazzzz20
ID: 8187799
Hi leavinmate.

I tried all the control characters (including NULL) as you said but it's still combining packets :(

I have tried DoEvents. But it is also of no use. I even tried it in a loop of 10000, but again, it didn't work.

I'm currently using a Timer control to cause a delay of 15 seconds between commands. 15 seconds between any two SendData() call seems a suitable delay but even it combines data when network is a little bit high on traffic. I need a way which should never combine packets.

Anyhow thanks for helping me.

Regards.
0
 

Expert Comment

by:amaronjob
ID: 8192402

If your server returns any reply on successful execution of a command, you can use "DataArrival Event" and issue next command.

I am sure this will not help if your server not going to reply.
0
 

Expert Comment

by:amaronjob
ID: 8192405

If your server returns any reply on successful execution of a command, you can use "DataArrival Event" and issue next command.

I am sure this will not help if your server not going to reply.
0
 
LVL 2

Accepted Solution

by:
stretch71 earned 1000 total points
ID: 8192481
First point to note is that there is no guarantee that your receiving server will not coalesce your packets on the receiving end, and make all your hard work on the sending end useless.

Also, padding any packet with control characters is never really a good idea since you have no guarantee over how those packets may arrive and where packet splits may occur.  Routers and other networking gear may make a mess of any nicely formed data you send and could easily coalesce your packets mid transmission.

Anyway,  you need to do two few things from the client side to get it working

1.  Set the Winsock buffer to 0 (SO_SNDBUF) so that winsock will not buffer your packets and puts them on the wire immediately

2.  Set TCP_NODELAY so you don't have to wait for the ACK from the receiving end before sending another packet.

For more info see MS Knowledge base article 214397.

From what I read it looks like you only set TCP_NODELAY.  Hope that this helps.
0
 

Author Comment

by:jazzzz20
ID: 8192774
Hi amaronjob.

The server does not send a reply on successful execution of the command. Therefore DataArrival event can not be used :-(

Regards.
0
 

Author Comment

by:jazzzz20
ID: 8192805
Hi MrDark.

If we close the Winsock while it has some pending data (which needs to be sent) in the buffer, then it is lost.

We can cause a delay between SendData() and Close() but still it gives no surity that data has been sent and it will not lost due to closing of winsock.

wsk.Connect
wsk.SendData ("Command_1")
'****** DELAY ******
wsk.Close
wsk.Connect
wsk.SendData ("Command_2")
wsk.Close

Regards.
0
 

Author Comment

by:jazzzz20
ID: 8192855
Hi stretch71.

I didn't set the SO_SNDBUF to 0. Now I would try it.

I am currently reading the KB article that you told. I'll let you know the result after I set buffer value.

Regards.
0
 

Author Comment

by:jazzzz20
ID: 8193063
Hi stretch71.

I didn't set the SO_SNDBUF to 0. Now I would try it.

I am currently reading the KB article that you told. I'll let you know the result after I set buffer value.

Regards.
0
 

Expert Comment

by:MrDark
ID: 8199004
why don't you try the sendcomplete property before sending another command so your code will be:

wsk.SendData ("Command_1")
do until wsk.sendcomplete = true
loop
wsk.SendData ("Command_2")
do until wsk.sendcomplete = true
loop
wsk.SendData ("Command_3")
do until wsk.sendcomplete = true
loop
wsk.SendData ("Command_4")
 may be you will have to use a separate procedure 4 that :)
0
 

Expert Comment

by:MrDark
ID: 8199042
sorry man i was talking wrong :(
use the sendcomplete event. to do that you will have to make a separate variable that holds the next command so you code will be:

dim my_command as string

Private Sub wsk_SendComplete()
   wsk.SendData (my_command)
End Sub
0
 

Author Comment

by:jazzzz20
ID: 8219677
Hi stretch71 & MrDark.

It works fine when SO_SNDBUF is set to 0 and there is some delay between SendData() calls.

It works much better when SO_SNDBUF is set to 0 and SendComplete event is used for the next SendData() call (as MrDark told).

It means that SO_SNDBUF is must for both solutions. But SO_SNDBUF causes a problem. After setting SO_SNDBUF = 1,
when the application starts sending the commands by calling SendData(), the application stop responding to user events (like click on buttons, window position changed, resized, etc.). It starts responding the events again when all the commands are sent.

I even tried putting "DoEvents" between calls, to process pending events, but it's not working.

I would appreciate if it can be fixed because it's not good to see your application does not respond to user generated events.

Thanks & Regards.
0
 
LVL 2

Expert Comment

by:stretch71
ID: 8220925
Setting SO_SNDBUF = 1 means that your winsock control will have a 1 byte buffer.  It also means you are most likely going to be sending 1 data byte per packet.  If you also have TCP_NODELAY off then you will have to wait for a response to each of your packets and this could be slow.

The problem you really have relates to the lack of threading in VB6.

I can't remember off the top of my head but you will probably find that the SendData call is blocking.  This means your VB code won't actually continue until after the SendData call has completed, which means that you won't execute the doevents statement until all your data is sent.

Also, since VB6 doesn't thread you can't really prevent this behaviour in the program.  The only way to get around this is to either split you application (difficult/problematic), convert to c++ (messy), try to move to VB.NET and work with threading (do-able with a learning curve) or change your cursor to the hourglass before the senddata and back to normal once the calls have completed.  At least this way the user knows that something is happening and that they shouldn't panic, and it's very easy.

I know it's not the answer you are looking for, but I hope it helps.
0
 

Author Comment

by:jazzzz20
ID: 8222879
Hi stretch71.

I wish threading could be done in VB6 easily :-(

Your suggestions are indeed good, especially the suggestion of hour glass :-)

I think only MrDark is interested in answering the question besides you. Therefore I would wait for another day. If no one else answers the question, then the points are yours. But I would also give points to MrDark (without splitting this 250) because his solution can improve the result.

Regards.
0
 

Expert Comment

by:MrDark
ID: 8229176
Hi jazz,
why don't you try to put your send code in a timer?
0
 

Author Comment

by:jazzzz20
ID: 8231398
Hi MrDark.

I was checking it in the SendComplete event for the testing purpose. While I am already using timer control in the actual application as I told leavinmate.

I appreciate your help. As stretch71's answer is more correct therefore I am accepting his answer. But I am also initiating a new question for giving you points because you also gave helpful suggestions. Please collect your points:

http://www.experts-exchange.com/Programming/Programming_Languages/Visual_Basic/Q_20567542.html

Thanks & Regards.
0
 

Author Comment

by:jazzzz20
ID: 8231409
Hi.

I thank every one who suggested solutions for this problem. I appreciate your help.

Regards.
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

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

Having just graduated from college and entered the workforce, I don’t find myself always using the tools and programs I grew accustomed to over the past four years. However, there is one program I continually find myself reverting back to…R.   So …
This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
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…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
Suggested Courses

764 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