開發環境Delphi10.3.3
使用TIdTCPClient寫了一個用戶端小例子,使用網絡調試助手作為服務端(設定接收到用戶端資訊會自動傳回資料)。
通訊模式:短連接配接。用戶端連接配接--發送---等待資料---接收---斷開。此例子中用戶端不知道傳回資訊長度是多少。
問題:由于不确定服務端傳回資料多少,是以使用Socket.ReadBytes(dat,-1,False); -1:表示一直讀取直到逾時。本以為像ClientSocket那樣有多少資料就能讀到多少,結果試驗了不同長度的資料,讀取到的長度也不一樣。1000多個位元組沒問題,超過2920就會出現讀取不夠的情況(經常在2920出問題,但也不全是)。讀取結束後disconnect,再次connect就會抛出Already connected異常。
如果Socket.ReadBytes(dat,-1,False); 第二個參數設定為正數,表示要讀取的位元組數,如果實際傳回的小于參數則會一直等待到readtimeout,然後抛出逾時異常。如果大于參則讀取成功。但這兩種情況都是導緻再次connect抛出Already connected異常。
解決Already connected異常的辦法是idtcpclnt1.Socket.InputBuffer.Clear;
解決讀取資料不夠的辦法是循環調用Socket.ReadBytes(dat,-1,False);
改進後如下:
procedure TReadThread.Execute;
var
dat:TIdBytes;
msg:AnsiString;
count:Integer;
tcpclient:TIdTCPClient;
begin
FreeOnTerminate:=true;
try
tcpclient:=TIdTCPClient.Create();
with tcpclient do
begin
Host := Form1.edtIP.Text;
Port := StrToInt(Form1.edtPort.Text);
Connect;
Form1.mmo1.Lines.Add('connected') ;
Socket.Write('阿斯蒂芬',IndyTextEncoding_OSDefault);
Form1.mmo1.Lines.Add('等待接收') ;
Socket.ReadTimeout:=1000*6;//讀取逾時時間
if Socket.CheckForDataOnSource(1000*60) then//等待資料60秒,有資料傳回true
begin
repeat
SetLength(dat, 0);
Socket.ReadBytes(dat,-1,False);
count:=count+Length(dat);
msg:=BytesToString(dat,IndyTextEncoding_OSDefault);
Form1.mmo1.Lines.Add('資料長度:'+IntToStr(Length(dat))) ;
until (Socket.CheckForDataOnSource(500)=False);
Form1.mmo1.Lines.Add('總長度:'+IntToStr(count)) ;
end
else
begin
if Connected then
Form1.mmo1.Lines.Add('等待逾時')
else
Form1.mmo1.Lines.Add('已斷開連接配接') ;
end;
//關閉
if connected then
begin
if Socket.InputBufferIsEmpty then
Form1.mmo1.Lines.Add('true')
else
Form1.mmo1.Lines.Add('false');
Socket.InputBuffer.Clear;
DisConnect;
end;
end;
except
on E : Exception do
begin
Form1.mmo1.Lines.Add('異常:'+E.Message+'['+e.ClassName+']');
end;
end;
end;