Reputation: 367
I try to send a string from a tidtcpserver to a tidtcpclient in Delphi, but when i send a string the client receives nothing. I don't get any errors. I am using tstringstream because i want to send a base64 string(writeln/readln can't send/receive that much text) This is the send code in idtcpserver1:
procedure TForm1.sendtext(index:integer; txt:string);
var
StrStream:tStream;
List: TList;
AContext: TIdContext;
begin
txt := trim(txt);
strstream := TMemoryStream.Create;
strstream.Write(PAnsiChar(txt)^, Length(txt));
strstream.Position := 0;
List := idTcpServer1.Contexts.LockList;
AContext := TIdContext(List[index]);
AContext.Connection.IOHandler.write(StrStream);
idTcpServer1.Contexts.UnLockList;
end;
This is the read code in idtcpclient1
procedure TIndyClient.Execute;
var
StrStream:tStringStream;
receivedtext:string;
begin
StrStream := tstringstream.Create;
form1.IdTCPClient1.IOHandler.readstream(StrStream);
receivedtext := strstream.DataString;
if receivedtext = '' = false then
begin
showmessage(receivedtext);
end;
end;
Does anyone know what i am doing wrong?
Upvotes: 0
Views: 2972
Reputation: 596176
You are making a very common newbie mistake of mismatching the IOHandler.Write(TStream)
and IOHandler.ReadStream()
calls. By default, ReadStream()
expects the stream data to be preceded by the stream size, but Write(TStream)
does not send the stream size by default.
Try this instead:
procedure TForm1.sendtext(index: integer; const txt: string);
var
StrStream: TMemoryStream;
List: TList;
AContext: TIdContext;
begin
strStream := TMemoryStream.Create;
try
WriteStringToStream(StrStream, Trim(txt), enUTF8);
List := idTcpServer1.Contexts.LockList;
try
AContext := TIdContext(List[index]);
AContext.Connection.IOHandler.Write(StrStream, 0, True);
finally
idTcpServer1.Contexts.UnlockList;
end;
finally
StrStream.Free;
end;
end;
procedure TIndyClient.Execute;
var
StrStream: TMemoryStream;
receivedtext: string;
begin
StrStream := TMemoryStream.Create;
try
Form1.IdTCPClient1.IOHandler.ReadStream(StrStream, -1, False);
StrStream.Position := 0;
receivedtext := ReadStringFromStream(StrStream, enUTF8);
finally
StrStream.Free;
end;
if receivedtext <> '' then
begin
// ShowMessage() is not thread-safe...
MessageBox(0, PChar(receivedtext), PChar(Application.Title), MB_OK);
end;
end;
Alternatively, because the stream size is now being sent, the receiving code can use ReadString()
instead of ReadStream()
:
procedure TIndyClient.Execute;
var
receivedtext: string;
begin
with Form1.IdTCPClient1.IOHandler do
begin
// you can alternatively set the IOHandler.DefStringEncoding
// instead of passing the encoding as a parameter...
receivedtext := ReadString(ReadLongInt, enUTF8);
end;
if receivedtext <> '' then
begin
// ShowMessage() is not thread-safe...
MessageBox(0, PChar(receivedtext), PChar(Application.Title), MB_OK);
end;
end;
BTW, WriteLn()/ReadLn()
do not have any length restrictions, they can handle big strings as long as there is available memory (and the text being sent does not have any line breaks in it). You are probably being confused by ReadLn()
being subject to the IOHandler.MaxLineLength
, which is set to 16K characters by default, but you can bypass that:
procedure TForm1.sendtext(index: integer; const txt: string);
va
List: TList;
AContext: TIdContext;
begin
List := idTcpServer1.Contexts.LockList;
try
AContext := TIdContext(List[index]);
// you can alternatively set the IOHandler.DefStringEncoding
// instead of passing the encoding as a parameter...
AContext.Connection.IOHandler.WriteLn(Trim(txt), enUTF8);
finally
idTcpServer1.Contexts.UnlockList;
end;
end;
procedure TIndyClient.Execute;
var
receivedtext: string;
begin
// you can alternatively set the IOHandler.DefStringEncoding
// and IOHandler.MaxLineLength instead of passing them as parameters...
receivedtext := Form1.IdTCPClient1.IOHandler.ReadLn(LF, -1, MaxInt, enUTF8);
if receivedtext <> '' then
begin
// ShowMessage() is not thread-safe...
MessageBox(0, PChar(receivedtext), PChar(Application.Title), MB_OK);
end;
end;
Upvotes: 3