RE: SOCKET RECEIVE techniques...

New Message Reply Date view Thread view Subject view Author view Other groups

Subject: RE: SOCKET RECEIVE techniques...
From: Frank Swarbrick (Frank.Swarbrick@efirstbank.com)
Date: Wed Aug 13 2008 - 20:39:20 EDT


n 8/12/2008 at 10:32 AM, in message
<BAY103-W11E3FA9F0349062C933031D3700@phx.gbl>, [Leo] CSI
Int'l<leo_j_langevin@hotmail.com> wrote:
>>  Date: Mon, 11 Aug 2008 04:04:06 -0700> From: ifranzki@googlemail.com>
To: 
> vse-l@Lehigh.EDU> Subject: Re: SOCKET RECEIVE techniques...> > Leo,> >
couldn't 
> it ALWAYS happen that you don't receive as many data as you> expect, even

> with smaller sizes? TCP packets can get fragmented by any> in-between hop.

> So I'd say you should always use that logic to make> sure you really got 
> as many bytes as you expect. I agree it is very> unlikely that you get 80

> bytes in 2 chunks but it can happen. In worst> case you get every single 
> byte in a separate chunk....
>  
>> What about SEND? I assume SOCKET SEND only completes (i.e. posts the> 
> ECB) when all data has been sent? If not, you should also use the same> 
> technique here.
>  
> Once the data is issued with a SEND, the lower layers are responsible 
> for delivering it and will post it to the sending application when it is 
> delivered. It is the receiving end that has the responsibility of loading

> all of the data.


>> Regarding SEND: Is it still true that the SEND waits until it has> 
> received the TCP ACK for the data that has been sent? As you may know,> 
> this can cause serious performance problems due to delayed ACKs.> Normally

> TCP/IP stacks do not ACK incoming data immediately, because> there might 
> be more data to ACK, or data to be sent together with the> ACK. Typically

> TCP/IP stacks delay ACKs from 20-200 msec. In case you> send more data
that 
> fits into one chunk (e.g. several hundert kilo> bytes), you have to do 
> that on separate SENDs, each of them would wait> until it has received the

> ACK(s). With a delayed ACK of 200 msec, this> results in 5 SENDs per 
> second, which is awfully slow....
>  
> Well, it depends on how you design your client. You can be concerned 
> with performance, delivery, both, or neither!
>  
> For example, if used in a normal way, you send data, you wait for a POST 
> to be sure that it got there.
>
> You want better speed, do 10 SEND's with a unique ECB for each, then 
> check each one and go through a rotation until they are all done, or you 
> can even keep 10 in-flight at all times. It will be up to you to take care

> of all of the ECB checking. Now, if any of them fails, then all 
> subsequent will most likely fail too.
>  
> Use of "FAST=YES" will let you send and let the system take care of the 
> posting. You don't need a unique ECB since
> it is never posted. You send it, and it's gone. It still takes as long 
> to get there, but you are not waiting. It's great to use on CLOSE (no 
> waiting), but can be used on other functions.
>  
> However, if any of them fail, you won't ever know. So that's a bad 
> thing. Furthermore, if you only use FAST=YES and send out lots of them 
> faster than the other side can handle it, then the other side will close 
> the window (setting=zero) and then VSE will be stuck storing them 
> (store...store...store...gobble...gobble...gobble...) until the stack 
> runs out of storage and all kinds of bad things start to happen.
>  
> So you are stuck with several considerations at this point...
>  
> If you do 1 ECB for a SEND and wait, you will only suffer a performance 
> problem if the delivery is being impeded in some way - the other side has

> too much, something you can't manage, - the stack isn't getting any cycles

> because of CICS or some other process sucking up storage, something you 
> can't manage, - you are fragmenting datagrams and delivering them to your

> controller faster than it can handle, something you cannot manage, and so

> on. By "you" I mean the program.
>  
> I had done experimentation with queuing up a load of ECB's and 
> maintaining a list and going through them and always keeping 10 ready for

> posting, and there came a point where it made very little difference, and

> so one needs to ask if going through all of this hoop jumping to cause a 
> bit of performance improvement is really worth all of the CPU and design 
> time that you would be using up just to do it.
>  
> So what to do?
>  
> Personally, I would want to be sure that my data arrived, so I would not 
> use FAST=YES, and for speed-important products where you really want to 
> zoom, I would design subtask that would determine which ECB was posted 
> and post to a  secondary task to handle where it would get posted to, but

> for 99% of any products, I would just do "SEND->WAIT->SEND->WAIT".
>  
> Sometimes the theory of "performance" doesn't apply well in the real 
> world (has anyone EVER used those pages of formulas in the Power 
> installation and planning guide to determine, mathematically, the best 
> performing queue size and block size to use to save microseconds of 
> processing time?) And sometimes it does (sending large datagrams, even if

> they are bigger than the MTUSIZE will always give better performance than

> sending lots of small datagrams, and it is a common-sense approach to 
> program design).
>  
> For example, using your scenario of 20-200ms, that means that my 64k of 
> data (as I show in my example) would send at a rate of 320k-3.2meg/second.

> From my program's perspective, the 64k at 320k/second was practically 
> instant. For huge amounts of data, the difference COULD be more dramatic.
>  
> The above noted that there is a difference in waiting: 20-200 
> milliseconds. 
>  
> Is this difference based on something that the user can control, or is 
> it on something that he cannot control (as noted above). If you cannot 
> control the delay (the other side is really busy), then there is no point

> worrying about it. Do a good program design, and let the network 
> administrator handle the performance (connection types, partition 
> balancing, a better receiver platform, etc).
>  
> In my humble opinion, the reason for the delay should be more of a 
> concern then trying to symbolically bypass it (the data still has to get 
> out there, even if you do not wait, and it takes the same amount of time,

> and may get clogged along the way) and flooding storage and the network 
> with data that the other side isn't ready to work may not be the best 
> plan to use.
>  
> It's a bit of give an take.
>  
>> Using the Assembler SOCKET macro, you can get around that by using> 
> separate SRBLOCKs for the sends, and do the WAIT only after the SENDs> for

> all chunks have been done. For C-Socket based application, there> is a 
> setting in the $SOCKOPT phase: $OPTSNWT. It tells the stack to> complete 
> the send() call without waiting for completion. Is this> option still 
> available and functioning ?
>  
> Yes, $OPTSNWT is an equate that you can enable on $OPTBCF1. The default 
> is off for the same reasons that I mentioned about FAST=YES. You use it 
> at your own risk, and don't use it a lot. 

I've heard this before from John Rankin and perhaps others at CSI, but I
have a hard time agreeing with your assertions as to why this is a good
idea.  Please correct me if I am mis-stating what you are saying.  You seem
to be stating that after you send some data you want to wait to receive the
ACK before you send more data.  Your reasoning is that if you receive the
ACK this means that 'it got there'.  Conversely, and tell me if I am reading
too much in to this, if you do not receive an ACK it allows you to 'know'
what the last data was that was received by the peer (because it was the
last ACK'd thing you sent).

To the first point, you really cannot make any guarantee that an ACK means
that the peer application received and successfully processed that data. 
The only guarantee is that the peer TCP level received the data, and that at
some point in the future (hopefully sooner rather than later!) it will make
an attempt to deliver the data to the peer application.  You are not
notified, at least at that point, that the data was not delivered up to the
application.  Even if the TCP was able to deliver the data to the
application that does not mean that the application was able to handle it in
the expected manner.  Additionally, even when you *don't* receive an ACK,
that does not mean that the peer did not receive that particular data.  It's
poossible that it did receive it, responded with an ACK and passed it up to
the application who processed it.  But immediately after sending the ACK the
network 'went down' and did not recover until after you (as a sender) tried
and tried to resend it, finally timing out.  From your point of view that
last data was not received.  But in fact it was.  But does it really matter?
 All that really matters is that the entire "transmission", as it were,
failed at some point.  Unless you have a protocol that is smarter than FTP
is there really any way to recover?

My point being, is that you say that you "want to be sure that [your] data
arrived".  But, other than implementing an *application level* ack, you
simply *can't* be sure.  The ACK does not give you that assurance.  So why
even bother waiting for it?  If your protocol is a simple 'sink' type
protocol like (I think!!) FTP where you just send and send and send and the
peer simply receives the data and does something with it what exactly is the
point in waiting?  Just send all you can as fast as you can until the peer,
if necessary, says *hold on, not so fast!* and closes his window.  Once the
window is closed then yes, you should wait (at the TCP level).  But your
application should be able to continue to 'send' data.  TCP should just
buffer it, and only when the 'send buffer' (and I'm honestly not sure there
is such a thing in your TCP product, other than the application level
buffer) is full should it no longer accept data from the application.  This
is where the application would then say "please tell me when I can send
again" (I assume by posting an ECB).

To the second point, again I simply don't see where it is of any use, at an
application level, for you to know at what point the connection 'failed'. 
Because your assumption may very well be wrong.  It may be that the peer
application failed earlier but that the peer TCP level didn't realize it
until some time later.  So relying on that assumption will not do you any
good.  (I know this latter isn't that clear, but I don't know that I have a
good example to clarify...)

Anyway, I hope I am making some sort of sense.  All of my TCP programming
uses the BSD/C and EZASOKET interfaces, so I may have some misunderstandings
at how things work at the lower level macro socket interface.

Frank


New Message Reply Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b25 : Thu Aug 28 2008 - 19:35:13 EDT