Reputation: 4946
I have an error that is confusing the hell out of me. The following code sends a line from a TidTCPClient to a TidTCPServer. The first time it executes, it works perfectly. The second time it executes, and every time after that, it adds a line break to the start of every string. What am I missing? (I know it does it in an odd way, but the list of clients is necessary in the full code)
procedure TClientForm.ButtonSendStringClick(Sender: TObject);
var
I: integer;
List: TList;
begin
List := ClientList.LockList;
try
for I := 0 to (List.Count- 1) do
begin
TidTCPClient(List[I]).IOHandler.WriteLn('Hello'+'|x|');
end;
finally
ClientList.UnlockList;
end;
Edit1.Text := '';
end;
procedure TClientForm.IdTCPServer1Execute(AContext: TIdContext);
var
LLine: string;
begin
LLine := Acontext.Connection.IOHandler.ReadLn('|x|');
OutputDebugString(PChar(LLine));
end;
Upvotes: 2
Views: 2551
Reputation: 597036
WriteLn()
appends a CRLF to the end of the string you pass to it, but ReadLn()
stops reading when it encounters the terminator string that you specify. So you are sending 'Hello|x|#13#10'
but you are only reading 'Hello|x|'
, leaving #13#10
in the socket buffer for the next read to grab.
To solve your problem, you have two choices:
1) If you want to keep using a custom terminator in ReadLn()
, change WriteLn()
to Write()
so the implicit CRLF is not sent anymore. No change is needed in your ReadLn()
call.
Write('Hello|x|');
LLine := ReadLn('|x|');
2) Stop using a custom terminator altogether. Pass just your main string by itself to WriteLn()
and let it append a CRLF, then do not pass any terminator to ReadLn()
as its default terminator is LF (which includes handling for CRLF).
WriteLn('Hello');
LLine := ReadLn();
Upvotes: 3
Reputation: 11859
I see a potential problem in your client code, ClientList.unlocklist
should be executed outside your loop:
procedure TClientForm.ButtonSendStringClick(Sender: TObject);
var
I: integer;
List : TList;
begin
List := ClientList.LockList;
try
for I := 0 to (List.Count- 1) do
begin
ShowMessage('Text to encrypt is ' + Edit1.Text);
TidTCPClient(List[I]).IOHandler.WriteLn((Encrypt(Edit1.Text,'Pass')+'|x|'));
end;
finally
ClientList.UnlockList;
end;
Edit1.Text := '';
end;
Do not use showmessage in the execute event of your server, since this is not the main GUI thread you must use synchronize
or use another logging method.
An other potential problem is the fact that your encrypted string may contain carriage return characters or even null characters (#0) in those cases the Readln
method of your server will be unable to read the entire encrypted string and so fail to decrypt.
One way to resolve this is to use base64 encoding
.
EDIT
The problem lies in the fact that you are using the '|x|' terminator in combination with ReadLn. Since you are using writeln from the client side you can do this
procedure TClientForm.IdTCPServer1Execute(AContext: TIdContext);
var
LLine: string;
begin
LLine := Acontext.Connection.IOHandler.ReadLn;
OutputDebugString(PChar(LLine));
end;
If you want to use a terminator don't use writeln
and readln
Upvotes: 2