Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Oct : Re: Assured Minimum Size

www.cryer.info
Managed Newsgroup Archive

Re: Assured Minimum Size

Subject:Re: Assured Minimum Size
Posted by:"Remy Lebeau (TeamB)" (no.spam@no.spam.com)
Date:Thu, 5 Oct 2006 10:45:21

"Allan Fernandes" <tech@ssmiths.com> wrote in message
news:452515d9$1@newsgroups.borland.com...

> I was checking out Sendbuf() with non-blocking sockets. Did not
> know how to trigger OnWrite.

You do not trigger it yourself.  It is triggered automatically by the socket
when needed, just like the OnRead event is triggered automatically.

> Checked the Internet and found a crude method, but it works.

That is the completely wrong thing to do.  You are not using the socket
correctly now.

> coming back to my earlier question, will this method assure me of
> at least 1Kb of transfer per receive at the Server's end.

No.  Nothing you can do can guarantee that.  Your reads must take into
account the actual size of each received packet.  You must cache the
incoming packets in memory, and then process the cached data as needed when
complete blocks are available.  Which means you must format your data in
such a way that you can differentiate between separate blocks.  For example:

    type
        TSocketBuffer = class(TMemoryStream)
        public
            procedure Compact;
            function Expand(ASize: Integer): Pointer;
            procedure Flush(ASocket: TCustomWinSocket);
            function Send(ASocket: TCustomWinSocket; const ABuffer; ASize:
Integer): Boolean;
            function ReadString(var VStr: String): Boolean;
            function SendString(ASocket: TCustomWinSocket; const AStr:
String): Boolean;
        end;

    procedure TSocketBuffer.Compact;
    var
        I: Integer;
        P: PByte;
    begin
        Position > 0 then
        begin
            I := Size - Position;
            if I > 0 then
            begin
                P := PByte(Memory);
                Move(P[Position], Memory, I);
                Size := I;
            end else
                Clear;
        end;
    end;

    function TSocketBuffer.Expand(ASize: Integer): Pointer;
    var
        Old: Integer;
        P: PByte;
    begin
        Old := Size;
        Size := (Old + ASize);
        P := PByte(Memory);
        Result := @P[Old];
    end;

    procedure TSocketBuffer.Flush(ASocket: TCustomWinSocket);
    var
        P: PByte;
        I: Integer;
    begin
        Position := 0;
        P := PByte(Memory);

        while Position < Size do
        begin
            I := ASocket.SendBuf(P[Position], Size - Position);
            if I < 1 then Break;
            Seek(I, soFromCurrent);
        end;

        Compact;
    end;

    function TSocketBuffer.Send(ASocket: TCustomWinSocket; const ABuffer;
ASize: Integer): Boolean;
    var
        P: PByte;
        I: Integer;
    begin
        Result := False;
        P := PByte(ABuffer);

        if Size = 0 then
        begin
            while ASize > 0 do
            begin
                I := ASocket.SendBuf(P, ASize);
                if I < 0 then
                begin
                    if WSAGetLastError <> WSAEWOULDBLOCK then Exit;
                    Break;
                end;
                if I = 0 then Exit; // disconnected
                Inc(P, I);
                Dec(ASize, I);
            end;
        end;

        if ASize > 0 then
        begin
            Seek(0, soFromEnd);
            Write(P, ASize);
        end;

        Result := True;
    end;

    function TSocketBuffer.ReadString(var VStr: String): Boolean;
    var
        I :Integer;
    begin
        Result := False;
        VStr := '';
        if (Size - Position) >= SizeOf(Integer) then
        begin
            Read(@I, SizeOf(I));
            if (Size - Position) >= I then
            begin
                if I > 0 then
                begin
                    SetLength(VStr, I);
                    Read(VStr[1], I);
                end;
                Result := True;
            end else
                Seek(-SizeOf(Integer), soFromCurrent);
        end;
    end;

    function TSocketBuffer.SendString(ASocket: TCustomWinSocket; const AStr:
String): Boolean;
    var
        I: Integer;
    begin
        I := Length(AStr);
        Result := Send(ASocket, @I, SizeOf(Integer));
        if Result then
            Result := SendBuffer(ASocket, PChar(AStr), I);
    end;


    --- client ---

    var
        OutboundBuffer: TSocketBuffer;

    constructor TForm1.Create(AOwner: TComponent);
    begin
        inherited Create(AOwner);
        OutboundBuffer := TSocketBuffer.Create;
    end;

    destructor TForm1.Destroy;
    begin
        OutboundBuffer.Free;
        inherited Destroy;
    end;

    procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket:
TCustomWinSocket);
    begin
        OutboundBuffer.Clear;
    end;

    procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket:
TCustomWinSocket);
    begin
        OutboundBuffer.Clear;
    end;

    procedure TForm1.ClientSocket1Write(Sender: TObject; Socket:
TCustomWinSocket);
    begin
        OutboundBuffer.Flush(Socket);
    end;

    procedure TForm1.ButtonSendDataClick(Sender: TObject);
    begin
        TSocketBuffer.SendString(ClientSocket1.Socket,
'abcdefghijklmnop.....');
    end;


    --- sender ---

    procedure TForm1.ServerSocket1Connect(Sender: TObject; Socket:
TCustomWinSocket);
    begin
        Socket.Data := TSocketBuffer.Create;
    end;

    procedure TForm1.ServerSocket1Disconnect(Sender: TObject; Socket:
TCustomWinSocket);
    begin
        TSocketBuffer(Socket.Data).Free;
        Socket.Data := nil;
    end;

    procedure TForm1.ServerSocket1Read(Sender: TObject; Socket:
TCustomWinSocket);
    var
        InboundBuffer: TSocketBuffer;
        I, Old: Integer;
        S: String;
    begin
        InboundBuffer := TSocketBuffer(Socket.Data);

        I := Socket.ReceiveLength;
        if I < 1 then Exit;

        Old := InboundBuffer.Size;
        P := InboundBuffer.Expand(I);

        I := Socket.ReceiveBuf(P, I);
        if I < 0 then
        begin
            InboundBuffer.Size := Old;
            Exit;
        end;

        InboundBuffer.Size := (Old + I);
        InboundBuffer.Position := 0;

        while InboundBuffer.ReadString(S) do
            // use S as needed ...

        InboundBuffer.Compact;
    end;


Gambit

Replies:

none

In response to:

www.cryer.info
Managed Newsgroup Archive