Board index » delphi » tcp flow control, event driven, low cpu usage ?

tcp flow control, event driven, low cpu usage ?


2003-09-07 09:33:58 AM
delphi218
Is it possible for a programmer to use TCP as a flow control mechanisme in
an event driven way so that cpu is only used when necessary.
The opposite would be 'polling': constantly calling send/receive to see if
it's possible to send/receive data ( this would use a lot of cpu ).
The event driven way would give the programmer a signal when more data can
be sent and when more data can be received.
Unfortunately the delphi TclientSocket/TserverSocket components only give
one OnWrite event to signal that data can be sent...
After data is sent and received on the other side... no more OnWrite events
follow... so the program doesn't know when it is ok to send the next data.
I wonder why that is ?
Is that a winsock limitation ? Is winsock not able to give signals in an
event driven/low cpu usage kind of way when the next data can be sent... or
is it maybe a tcp protocol limitation... or is it just a delphi socket
components limitation ?
Thx for any help,
Skybuck.
 
 

Re:tcp flow control, event driven, low cpu usage ?

"Skybuck Flying" <XXXX@XXXXX.COM>writes
Quote
Is it possible for a programmer to use TCP as a flow control mechanisme
in an event driven way so that cpu is only used when necessary.
Yes.
Quote
The opposite would be 'polling': constantly calling send/receive to see
if it is possible to send/receive data ( this would use a lot of cpu ).
As much as it can, in fact.
Quote
The event driven way would give the programmer a signal when more data
can be sent and when more data can be received.

Unfortunately the delphi TclientSocket/TserverSocket components only give
one OnWrite event to signal that data can be sent...

After data is sent and received on the other side... no more OnWrite
events follow... so the program doesn't know when it is ok to send the
next data.

Is that a winsock limitation ? Is winsock not able to give signals in an
event driven/low cpu usage kind of way when the next data can be sent...
or is it maybe a tcp protocol limitation... or is it just a delphi socket
components limitation ?
I don't use Delphi, but the answer is probably "No" to all the above. In
Winsock itself, FD_WRITE events - which tell you that it is OK to send data -
for both WSAAsyncSelect and WSAEventSelect are "edge triggered".
The Delphi components will almost certainly be implemented using one of
these methods. This would mean the OnWrite event occurs when the socket
changes from "not writeable" to "writeable". Again, assuming the components
work like Winsock, the other edge (when the socket changes from "writeable"
to "not writeable") will be somehow indicated by whatever the "send"
function is called.
For example, suppose you are implementing an HTTP server. After accepting a
client connection, you will receive read event(s) for the client's request.
When you've received the entire request, you start sending the response
immediately, in a loop that continues until you are done or you find you
cannot send any more. In the latter case, you should then store where you
got up to.
Some time later, a write event will occur. In response to this, you look at
where you got up to, and repeat the process above: loop sending until you
are done or can not send any more. Again, if you're not finished, you store
your progress so you can continue on the next write event.
Alex
 

Re:tcp flow control, event driven, low cpu usage ?

"Alex Fraser" <XXXX@XXXXX.COM>writes:
Quote
>Is that a winsock limitation ? Is winsock not able to give signals in an
>event driven/low cpu usage kind of way when the next data can be sent...
>or is it maybe a tcp protocol limitation... or is it just a delphi socket
>components limitation ?
Skybuck: delphi socket component most likely. In "C", you won't find such
limitations as the entire system is available to you. Most notably,
CreateIoCompletionPort/GetQueuedCompletionStatus
Alex: careful, this clown is troll. He can clean his left ear with a really
long Q-tip from his right ear, if you know what I am saying?
--
David Gravereaux <XXXX@XXXXX.COM>
$ make war
make: *** No rule to make target `war'. Stop. Try `love' instead.
 

Re:tcp flow control, event driven, low cpu usage ?

Quote
Alex: careful, this clown is troll. He can clean his left ear with a
really
long Q-tip from his right ear, if you know what I am saying?
lol!
--
The designer of the experimental, SMP and HyperThread friendly, AppCore
library.
AppCore.home.comcast.net
 

Re:tcp flow control, event driven, low cpu usage ?

"Alex Fraser" <XXXX@XXXXX.COM>writes
Quote
"Skybuck Flying" <XXXX@XXXXX.COM>writes
news:bje1u5$ocg$XXXX@XXXXX.COM...
>Is it possible for a programmer to use TCP as a flow control mechanisme
>in an event driven way so that cpu is only used when necessary.

Yes.

>The opposite would be 'polling': constantly calling send/receive to see
>if it is possible to send/receive data ( this would use a lot of cpu ).

As much as it can, in fact.

>The event driven way would give the programmer a signal when more data
>can be sent and when more data can be received.
>
>Unfortunately the delphi TclientSocket/TserverSocket components only
give
>one OnWrite event to signal that data can be sent...
>
>After data is sent and received on the other side... no more OnWrite
>events follow... so the program doesn't know when it is ok to send the
>next data.
>
>Is that a winsock limitation ? Is winsock not able to give signals in an
>event driven/low cpu usage kind of way when the next data can be sent...
>or is it maybe a tcp protocol limitation... or is it just a delphi
socket
>components limitation ?

I don't use Delphi, but the answer is probably "No" to all the above. In
Winsock itself, FD_WRITE events - which tell you that it is OK to send
data -
for both WSAAsyncSelect and WSAEventSelect are "edge triggered".

The Delphi components will almost certainly be implemented using one of
these methods. This would mean the OnWrite event occurs when the socket
changes from "not writeable" to "writeable". Again, assuming the
components
work like Winsock, the other edge (when the socket changes from
"writeable"
to "not writeable") will be somehow indicated by whatever the "send"
function is called.
Sounds reasonable :D I think the delphi component works that way :D
Quote

For example, suppose you are implementing an HTTP server. After accepting
a
client connection, you will receive read event(s) for the client's
request.
When you've received the entire request, you start sending the response
immediately, in a loop that continues until you are done or you find you
cannot send any more. In the latter case, you should then store where you
got up to.
while (not done) or (cant send anymore) do
begin
try to send;
end;
Ok... at first glance, this loop looks cpu intensive...
The question is how long will this loop run ?
Maybe until the TCP buffer or TCP window size is full ???
If that would be the case... then that is how TCP flow control works....
Makes me wonder what happens if TCP window size is large like 1 megabyte...
Quote
Some time later, a write event will occur. In response to this, you look
at
where you got up to, and repeat the process above: loop sending until you
are done or can not send any more. Again, if you're not finished, you store
your progress so you can continue on the next write event.
Hmm interesting... so when the loop can't send anymore.. it should just
stop...
Then later an OnWrite is fired again... and the loop can run again.. taking
off where it left :D
Ok... I think I get it... Thx for your explanation...
Now I am justing hoping that the loop won't hang the system to much :D
Hmmm...
Bye,
Skybuck.
 

Re:tcp flow control, event driven, low cpu usage ?

"Alex Fraser" <XXXX@XXXXX.COM>writes
Quote
"Skybuck Flying" <XXXX@XXXXX.COM>writes
news:bje1u5$ocg$XXXX@XXXXX.COM...
>Is it possible for a programmer to use TCP as a flow control mechanisme
>in an event driven way so that cpu is only used when necessary.

Yes.

>The opposite would be 'polling': constantly calling send/receive to see
>if it is possible to send/receive data ( this would use a lot of cpu ).

As much as it can, in fact.

>The event driven way would give the programmer a signal when more data
>can be sent and when more data can be received.
>
>Unfortunately the delphi TclientSocket/TserverSocket components only
give
>one OnWrite event to signal that data can be sent...
>
>After data is sent and received on the other side... no more OnWrite
>events follow... so the program doesn't know when it is ok to send the
>next data.
>
>Is that a winsock limitation ? Is winsock not able to give signals in an
>event driven/low cpu usage kind of way when the next data can be sent...
>or is it maybe a tcp protocol limitation... or is it just a delphi
socket
>components limitation ?

I don't use Delphi, but the answer is probably "No" to all the above. In
Winsock itself, FD_WRITE events - which tell you that it is OK to send
data -
for both WSAAsyncSelect and WSAEventSelect are "edge triggered".

The Delphi components will almost certainly be implemented using one of
these methods. This would mean the OnWrite event occurs when the socket
changes from "not writeable" to "writeable". Again, assuming the
components
work like Winsock, the other edge (when the socket changes from
"writeable"
to "not writeable") will be somehow indicated by whatever the "send"
function is called.

For example, suppose you are implementing an HTTP server. After accepting
a
client connection, you will receive read event(s) for the client's
request.
When you've received the entire request, you start sending the response
immediately, in a loop that continues until you are done or you find you
cannot send any more. In the latter case, you should then store where you
got up to.
Which method would be best for receiving... ?
1. When OnRead event is fired read only one buffer...
or
2. When OnRead event is fired use a loop to read until you are done or no
more data can be received ?
( opposite of sending ).
I will try all methods and see which work best :D
 

Re:tcp flow control, event driven, low cpu usage ?

"Skybuck Flying" <XXXX@XXXXX.COM>writes
Quote
Hmm.. the problem remains, if the server closes first... while the
client is still sending then the client will get error 10053
What would you expect to happen?
Quote
// client code:

procedure TForm1.ClientSocket1Write(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add('write');

repeat

ClientSize := 1400;

// if socket is still connected then
if Socket.Connected then
begin

ClientBytes := Socket.SendBuf( ClientData, ClientSize );
// error 10053 ?!

if ClientBytes>0 then
begin
ClientBytesSent := ClientBytesSent + ClientBytes;
end;

end;

until (ClientBytes = -1) or (ClientBytes = 0) or (not
Socket.Connected);
end;
The Socket.Connected tests are probably redundant - whenever
Socket.Connected would return 'false', calling the send/recv functions
should also indicate an error. In other words, you're effectively checking
twice.
If ClientSize is not zero, ClientBytes cannot be zero. There isn't a special
meaning as there is for receiving data.
In short, for the sending side, your code two posts ago looked fine.
You asked in a previous post, "How long will [the send] loop run?" The
answer is that, with the socket set to non-blocking, it will run until the
send call would block (or you're done, or there's an error). The send call
must block if there is no space in the send buffer.
Quote
// server code:

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo2.Lines.Add('client read');

repeat

// if socket is sill valid then
if Socket.Connected then
begin

ServerSize := 1400;
ServerBytes := Socket.ReceiveBuf( ServerData, ServerSize );

if ServerBytes>0 then
begin
ServerBytesReceived := ServerBytesReceived + ServerBytes;
end;

end;

until (ServerBytes = -1) or (ServerBytes = 0) or (not
Socket.Connected);
end;
Again, the Socket.Connected tests are probably redundant, and it is probably
better without the loop (ie one read per OnRead event). In Winsock itself,
read events are "level" triggered, so if you don't read all the available
data, another event is generated.
You'll still need to check ServerBytes though, even without the loop. As I
implied above, 0 has a special meaning: the connection has been gracefully
closed.
Alex
 

Re:tcp flow control, event driven, low cpu usage ?

"Alex Fraser" <XXXX@XXXXX.COM>writes:
Quote
In Winsock itself,
read events are "level" triggered, so if you don't read all the available
data, another event is generated.
Unless your using event object, you won't get another notice until you've
drained it dry.
--
David Gravereaux <XXXX@XXXXX.COM>
$ make war
make: *** No rule to make target `war'. Stop. Try `love' instead.
 

Re:tcp flow control, event driven, low cpu usage ?

"David Gravereaux" <XXXX@XXXXX.COM>writes
Quote
"Alex Fraser" <XXXX@XXXXX.COM>writes:

>In Winsock itself, read events are "level" triggered, so if you don't
>read all the available data, another event is generated.

Unless your using event object, you won't get another notice until you've
drained it dry.
No, what I wrote applies to both WSAEventSelect and WSAAsyncSelect.
Alex
 

Re:tcp flow control, event driven, low cpu usage ?

"Alex Fraser" <XXXX@XXXXX.COM>writes:
Quote
"David Gravereaux" <XXXX@XXXXX.COM>writes
news:XXXX@XXXXX.COM...
>"Alex Fraser" <XXXX@XXXXX.COM>writes:
>
>>In Winsock itself, read events are "level" triggered, so if you don't
>>read all the available data, another event is generated.
>
>Unless your using event object, you won't get another notice until you've
>drained it dry.

No, what I wrote applies to both WSAEventSelect and WSAAsyncSelect.
Not from what I found with WSAEventSelect. If you don't get all of it, you'll
never get another FD_READ. I had to loop on WSARecv until SOCKET_ERROR. If I
didn't loop, my event wouldn't have become signaled again. I think the full
drain caused the reset. Maybe if I didn't get all of it and had manually reset
the event...? But this is old code and I won't be using it again..
unsigned CEvSockets::RecvThreadHandler::ThreadHandlerProc(void) {
WSANETWORKEVENTS neInfo;
DWORD dwEvent;
while (1) {
// go to sleep on the socket and stop kernal objects
dwEvent = cwcEvents.Wait(FALSE, INFINITE);
// validate return, not shown.
// OK, what happened while we were asleep?
m_csoSocketEvent.EnumNetEvents(m_s, &neInfo);
if (neInfo.lNetworkEvents & FD_READ) {
//ThrowMsg("Data has arrived");
CInBuff *pib;
//CInBuff *&rib = pib;
int nError;
bool done = false;
DWORD NumBytes,Flags=0;
while (!done) {
if (!m_fbs.Pop(pib,0)) {
pib = new CInBuff;
ThrowMsg("Buffer upgrade!");
}
nError = WSARecv(m_s, *pib, 1, &NumBytes, &Flags, NULL, NULL);
if (nError == SOCKET_ERROR) {
m_fbs.Push(pib);
done = true;
continue;
}
if (!NumBytes) {
ThrowMsg("Gracefull disconnection!");
closesocket(m_s);
return 1;
}
pib->UsedBytes = NumBytes;
m_rbq.Put(pib);
}
}
--
David Gravereaux <XXXX@XXXXX.COM>
$ make war
make: *** No rule to make target `war'. Stop. Try `love' instead.
 

Re:tcp flow control, event driven, low cpu usage ?

In article <XXXX@XXXXX.COM>, David Gravereaux
<XXXX@XXXXX.COM>writes:
Quote
Not from what I found with WSAEventSelect. If you don't get all of it, you'll
never get another FD_READ. I had to loop on WSARecv until SOCKET_ERROR. If I
didn't loop, my event wouldn't have become signaled again. I think the full
drain caused the reset. Maybe if I didn't get all of it and had manually reset
the event...? But this is old code and I won't be using it again..
Strange - I have been heading into the area of WSAEventSelect pretty strongly
lately, and I have operated on the assumption that FD_READ will be called if
there's data left in the buffer after I called recv().
Your events are _manual_ reset events, yes? (Or created by
WSACreateEvent())
Alun.
~~~~
[Please don't email posters, if a Usenet response is appropriate.]
--
Texas Imperial Software | Find us at www.wftpd.com or email
1602 Harvest Moon Place | XXXX@XXXXX.COM.
Cedar Park TX 78613-1419 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(512)258-9858 | Try our NEW client software, WFTPD Explorer.
 

Re:tcp flow control, event driven, low cpu usage ?

XXXX@XXXXX.COM (Alun Jones [MS MVP]) writes:
Quote
In article <XXXX@XXXXX.COM>, David Gravereaux
<XXXX@XXXXX.COM>writes:
>Not from what I found with WSAEventSelect. If you don't get all of it, you'll
>never get another FD_READ. I had to loop on WSARecv until SOCKET_ERROR. If I
>didn't loop, my event wouldn't have become signaled again. I think the full
>drain caused the reset. Maybe if I didn't get all of it and had manually reset
>the event...? But this is old code and I won't be using it again..

Strange - I have been heading into the area of WSAEventSelect pretty strongly
lately, and I have operated on the assumption that FD_READ will be called if
there's data left in the buffer after I called recv().

Your events are _manual_ reset events, yes? (Or created by
WSACreateEvent())
I had use CreateEvent for the multithread class library it uses, but I do
remember them being manual reset. The docs say to use manual reset events, yes?
--
David Gravereaux <XXXX@XXXXX.COM>
$ make war
make: *** No rule to make target `war'. Stop. Try `love' instead.
 

Re:tcp flow control, event driven, low cpu usage ?

David Gravereaux <XXXX@XXXXX.COM>writes:
Quote
XXXX@XXXXX.COM (Alun Jones [MS MVP]) writes:

>In article <XXXX@XXXXX.COM>, David Gravereaux
><XXXX@XXXXX.COM>writes:
>>Not from what I found with WSAEventSelect. If you don't get all of it, you'll
>>never get another FD_READ. I had to loop on WSARecv until SOCKET_ERROR. If I
>>didn't loop, my event wouldn't have become signaled again. I think the full
>>drain caused the reset. Maybe if I didn't get all of it and had manually reset
>>the event...? But this is old code and I won't be using it again..
>
>Strange - I have been heading into the area of WSAEventSelect pretty strongly
>lately, and I have operated on the assumption that FD_READ will be called if
>there's data left in the buffer after I called recv().
>
>Your events are _manual_ reset events, yes? (Or created by
>WSACreateEvent())


I had use CreateEvent for the multithread class library it uses, but I do
remember them being manual reset. The docs say to use manual reset events, yes?
Ohhh. I see what I was doing wrong. I was waiting with WaitForMultipleObjects
because I had an interrupt stop event. WSAEnumNetworkEvents is the reset
mechanism, but I wasn't using it for the wait feature...
Sure is fun reading old code and spotting errors that I missed 4 years ago :)
--
David Gravereaux <XXXX@XXXXX.COM>
$ make war
make: *** No rule to make target `war'. Stop. Try `love' instead.
 

Re:tcp flow control, event driven, low cpu usage ?

"Alex Fraser" <XXXX@XXXXX.COM>writes
Quote
"Skybuck Flying" <XXXX@XXXXX.COM>writes
news:bjge6j$q2t$XXXX@XXXXX.COM...
>Hmm.. the problem remains, if the server closes first... while the
>client is still sending then the client will get error 10053

What would you expect to happen?
Well to be honest, I exptected:
1. The client to disconnect...
2. The client.socket.connected would become false.
3. The client.socket.sendbuf call would silently fail and return -1 or 0 :D
Then there is another weird thing... in case of errors I'd expect them
to be return via the OnError event...
But I am getting the impression this is a lower error generated by lower
winsock code or something...
At the moment I am not sure what happens... I have been playing games :D so as
soon as I am done with them and have some 'free' time I will look into this
:D... Maybe I will find out what happens or maybe there is nothing to find
out :D
I can imagine this to be a common problem...
1. The client is still sending when the server shutsdown.
or vice versa:
2. The server is still sending when the client shutsdown.
Is TCP able to gracefully shutdown under these circumstances ?
If so then there must be something wrong with the code/concept/algorithm ?
If not then one would need an extra protocol to gracefully shutdown.
Quote

>// client code:
>
>procedure TForm1.ClientSocket1Write(Sender: TObject;
>Socket: TCustomWinSocket);
>begin
>Memo1.Lines.Add('write');
>
>repeat
>
>ClientSize := 1400;
>
>// if socket is still connected then
>if Socket.Connected then
>begin
>
>ClientBytes := Socket.SendBuf( ClientData, ClientSize );
>// error 10053 ?!
>
>if ClientBytes>0 then
>begin
>ClientBytesSent := ClientBytesSent + ClientBytes;
>end;
>
>end;
>
>until (ClientBytes = -1) or (ClientBytes = 0) or (not
>Socket.Connected);
>end;

The Socket.Connected tests are probably redundant - whenever
Socket.Connected would return 'false', calling the send/recv functions
should also indicate an error. In other words, you're effectively checking
twice.
The idea was to first check if the connection is still open... if so then
it's safe to call sendbuf...
If the connection is closed... then no call to sendbuff should be made...
and so no error would be generated...
So it is kinda weird that an error is generated... that would mean this
connected property is not 'working' as planned.
Quote
If ClientSize is not zero, ClientBytes cannot be zero. There isn't a
special
meaning as there is for receiving data.

In short, for the sending side, your code two posts ago looked fine.

You asked in a previous post, "How long will [the send] loop run?" The
answer is that, with the socket set to non-blocking, it will run until the
send call would block (or you're done, or there's an error). The send call
must block if there is no space in the send buffer.
( Ok, the code is using non-blocking sockets. )
Quote

>// server code:
>
>procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
>Socket: TCustomWinSocket);
>begin
>Memo2.Lines.Add('client read');
>
>repeat
>
>// if socket is sill valid then
>if Socket.Connected then
>begin
>
>ServerSize := 1400;
>ServerBytes := Socket.ReceiveBuf( ServerData, ServerSize );
>
>if ServerBytes>0 then
>begin
>ServerBytesReceived := ServerBytesReceived + ServerBytes;
>end;
>
>end;
>
>until (ServerBytes = -1) or (ServerBytes = 0) or (not
>Socket.Connected);
>end;

Again, the Socket.Connected tests are probably redundant, and it's
probably
better without the loop (ie one read per OnRead event). In Winsock itself,
read events are "level" triggered, so if you don't read all the available
data, another event is generated.

You'll still need to check ServerBytes though, even without the loop. As I
implied above, 0 has a special meaning: the connection has been gracefully
closed.
I wonder if the client socket works that way too... I ll bet it probably
does... but for someone reason... the sendbuf
is still called... and generates an error... maybe it is an exception... :D
Later,
Skybuck.
 

Re:tcp flow control, event driven, low cpu usage ?

In article <XXXX@XXXXX.COM>, David Gravereaux
<XXXX@XXXXX.COM>writes:
Quote
I had use CreateEvent for the multithread class library it uses, but I do
remember them being manual reset. The docs say to use manual reset events,
yes?
Yes, they do.
Actually, you should be using WSACreateEvent. The fact that they're the
same as manual reset Win32 events should not be something you care about.
I'm concerned, because I would have run into significant problems by now if your
assertion is correct.
Alun.
~~~~
[Please don't email posters, if a Usenet response is appropriate.]
--
Texas Imperial Software | Find us at www.wftpd.com or email
1602 Harvest Moon Place | XXXX@XXXXX.COM.
Cedar Park TX 78613-1419 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(512)258-9858 | Try our NEW client software, WFTPD Explorer.