Newsgroups : Borland : borland.public.delphi.internet.winsock : 2008 Jan : Re: TClientSocket write progress???

www.cryer.info
Managed Newsgroup Archive

Re: TClientSocket write progress???

Subject:Re: TClientSocket write progress???
Posted by:"Remy Lebeau (TeamB)" (no.spam@no.spam.com)
Date:Thu, 24 Jan 2008 14:44:52

"Bo Berglund" <bo.berglund@telia.com> wrote in message
news:rg1ip3hp9ocl20fl4ijcudtl4s53n6fbkh@4ax.com...

> Will the OnWrite always fire following the writing to the
> socket of all data supplied in the SendText call?

No.  It is triggered once right after the socket is connected, to indicate
the socket is ready to accept data, and then is not triggered again until a
send operation would put the socket into a blocking state because it was
already busy doing something else.  The event tells you when the socket is
ready to accept new data for sending.  If you perform a send and it does not
report back WSAEWOULDBLOCK, then you can keep sending without waiting for
OnWrite.  But once WSAEWOULDBLOCK is reported, you can't send anything more
until OnWrite is triggered.

> For example, if I cut the data down to chunks of 10K or so
> and send them individually while waiting for OnWrite to fire
> after each send, will that work?

Even at 10K chunks, WAEWOULDBLOCK is still possible.  Even at 1 byte, for
that matter.  Look at the example code I pointed you to in my last reply.
It uses an asynchronous model to handle the OnWrite event whenever it
occurs.  I wrote it to use a helper class to manage it, but there are other
ways to manage it.  The gist is the same, though - as long as WSAEWOULDBLOCK
is not reported, you can loop the sending without stopping.  But once
WSAEWOULDBLOCK occurs, you have to cache your remaining data and then send
the cache when OnWrite is triggered.  WSAEWOULDBLOCK can occur even when
writing the cache, so be prepared for that as well.

> Something like this (simplified):

You are ignoring the return value of SendText() again.  You MUST use that
value.  If you pass 10000 bytes to SendText(), but it returns back 1000,
then only 1000 bytes were sent and you are throwing away 9000 bytes. You
also need the return value in order to know if the other party disconnected
on its end while you are still sending to it.  I already showed you how to
allow your loop to respond to OnWrite, and disconnects, in a single
function, ie:

    while Length(SendData) > 0 do
    begin
        Tel := Copy(SendData, 1, 10000);
        Sent := FSocket.Socket.SendText(Tel);
        if Sent < 0 then
        begin
            if WSAGetLastError <> WSAEWOULDBLOCK then
            begin
                // socket error...
                Break;
            end else
            begin
                // need to wait for OnWrite...
                FOnWriteFlag := False;
                repeat
                    Application.ProcessMessages;
                    Sleep(1);
                until FOnWriteFlag or (not FSocket.Socket.Connected);
            end;
        end
        else if Sent = 0 then
        begin
            // other party disconnected...
            Break;
        end else
        begin
            Delete(SendData, 1, Sent);
            Inc(ProgressCnt);
            ShowProgress(ProgressCnt);
        end;
    end;

If you use SendBuf() instead of SendText(), you can avoid the Copy() and
Delete() altogether for better performance:

    Index := 1;
    while Index <= Length(SendData) do
    begin
        Sent := FSocket.Socket.SendBuf(@SendData[Index],
Length(SendData)-Index+1);
        if Sent < 0 then
        begin
            if WSAGetLastError <> WSAEWOULDBLOCK then
            begin
                // socket error...
                Break;
            end else
            begin
                // need to wait for OnWrite...
                FOnWriteFlag := False;
                repeat
                    Application.ProcessMessages;
                    Sleep(10);
                until FOnWriteFlag or (not FSocket.Socket.Connected);
            end;
        end
        else if Sent = 0 then
        begin
            // other party disconnected...
            Break;
        end else
        begin
            Inc(Index, Sent);
            Inc(ProgressCnt);
            ShowProgress(ProgressCnt);
        end;
    end;

> I had thought of reducing (rather than expanding) traffic by zipping
> the file before sending it and then expanding it on target and also
> send it as a binary stream rather than ASCII.

All good choices, as long as the overhead of compressing the data does not
overshadow the speed in sending it.

> But I don't have anything that can unzip the compressed files...

TZipForge, for instance, supports both zipping and unzipping.  I'm sure
other zipping components/libraries do as well.  Also, an (older) version of
ZLib is included with Delphi, if I remember correctly.  That is commonly
used for sending compressed data over a socket (HTTP, FTP, and other
protocols have ZLib support, for example).


Gambit

Replies:

none

In response to:

www.cryer.info
Managed Newsgroup Archive