Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Oct : 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
none