TIdTCPServer 收發都沒有問題了,現在是 TIdTCPClient 監聽有問題了
TCPClient.Connect成功以后,會 創建一個執行緒
//創建執行緒
ThreadHandle := CreateThread(nil, 0, @TForm5.ClientListen, nil, 0, ThreadId);
下面就是仿照 TIdTCPServer 玩的,原來的 Socket.ReadLn 沒有問題,現在換成這個Socket.ReadBytes或者.IOHandler.ReadBytes,都出現一個問題,就是服務器端發送的位元組,客戶端沒有回應也就是 檢查len =0,但是客戶端發送位元組后,服務器照常接收,這個時候上次發給客戶端的位元組過來了,也就是檢查len>0了,很奇怪,也就是大家有什么好的建議
procedure TForm5.ClientListen;
var
len:integer;
s:string;
buffer:TBytes;
begin
while true do
begin
try
len :=Form5.TCPClient.Socket.InputBuffer.Size;
if len > 0 then
begin
//s :=Form5.TCPClient.Socket.ReadLn('');
Form5.TCPClient.Socket.ReadBytes(buffer, len, false);
//Form5.TCPClient.IOHandler.ReadBytes(buffer, len, false);
//轉化成字串
s := stringof(buffer);
Form5.SendConsole.Lines.Add(s);
end;
except
end;
end;
end;
uj5u.com熱心網友回復:
服務器端的邏輯有問題吧?本來嘛,Indy的機制是阻塞式的。
控制的不好就變成這樣了。
uj5u.com熱心網友回復:
服務器就是用buffer := bytesof(Edit3.Text);
BzAContext.Connection.IOHandler.Write(buffer);
BzAContext是在服務器連接成功后 procedure TForm5.TCPServerConnect(AContext: TIdContext);中獲得 BzAContext :=AContext;
這個服務器發的,服務器使用其他小工具sokit測驗過,沒有問題
uj5u.com熱心網友回復:
BzAContext是在服務器連接成功后 procedure TForm5.TCPServerConnect(AContext: TIdContext);中獲得 BzAContext :=AContext;你這個BzAContext有問題哦。
TForm5.TCPServerConnect(AContext: TIdContext) 中,AContext是會隨時改變的變數。
所以你這個BzAContext也隨時在變。
由此判斷你的程式寫得有問題。
你可以在onExecute事件用AContext答復客戶端試試能否收到回答。
uj5u.com熱心網友回復:
客戶端TIdTCPClient用執行緒監聽接收資料服務器TIdTCPServer在onExecute事件接收資料,每1個客戶端連接(引數AContext)相當于1個執行緒
資料到達時就自動觸發onExecute,TIdTCPServer會自己維護這個AContext
所以不須要在Connect事件中保存AContext
所有的連接都在IdTCPServer.Contexts里面,自己判斷Handle
uj5u.com熱心網友回復:
wylton我實驗了在onExecute事件用AContext直接答復客戶端也是收不到。
kaikai_kk
我理解你的意思,拿如果不使用這個零時AContext,我用什么來發給客戶端,因為總有情況是不在onExecute事件里發給客戶端,隨時可能在其他地方如一個按鈕觸發
我服務器使用我獲得的那個AContext,是可以發給 小工具 sokit ,他能夠正常接收,sokit 發出來的,我的服務器也可以正常接收到的,證明服務器是好的。客戶端還是有問題。
當時用WriteIn 和 ReadIn 服務器客戶端都可以,但是我還是要求收發位元組(不帶0d0a)的,這個就出了點問題
兩位仁兄可否給點你們寫的代碼,其他哥們朋友也可以幫個忙,謝謝
uj5u.com熱心網友回復:
你這個,這么看得那么別扭……啟動后,為什么還要開一個執行緒?
本來INDY設計是很明朗的,TCP,一個客戶,啟動一個執行緒,一對一。
uj5u.com熱心網友回復:
你能否貼出你服務端的代碼?uj5u.com熱心網友回復:
這是我客戶端的讀入var
RxBuf:TIdBytes;
CB----是我的另一結構變數
SetLength(RxBuf, SizeOf(CB)); //否則讀入不會改變
idTCPClient1.IOHandler.ReadBytes(RxBuf, SizeOf(CB), False);
Idglobal.BytesToRaw(RxBuf, CB, SizeOf (CB));
這樣cb就賦值了。
你的
var
len:integer;
s:string;
buffer:TBytes;
begin
buffer:TBytes;-----這個是否有問題呢?
uj5u.com熱心網友回復:
wylton,我讀取的東西,位元組大小不定的怎么辦,你的SizeOf(CB),明顯是一個定尺寸的讀取,不過你可以給我代碼,我可以借鑒,實驗一下了。多謝了,要是幫我考慮不定尺寸就好了,就像服務器端的len :=AContext.Connection.IOHandler.InputBuffer.Size;
if len > 0 then
begin
AContext.Connection.IOHandler.ReadBytes(buffer, len, false);
//轉化成字串
s := stringof(buffer);
Self.Console.Lines.Add(s);
end;
這個就可以玩的,好用的
uj5u.com熱心網友回復:
你服務端發送的代碼不貼出來,就讓別人猜測你的錯誤?SizeOf(服務器要發送的東西)其實都有固定的最大值。。所以檔案傳輸和大點的東西,都要分塊。
uj5u.com熱心網友回復:
樓上的哥們看看2樓就知道了吧,早就貼了出來了,還有其他哥們說我的BzAContext有問題,其實經過 小工具 sokit 測驗,服務器這邊都可以的。關鍵還是我這邊的客戶端的接收。我可以實驗一下你那樣的接收固定大小的,最好,有沒有不知道大小的,就是像服務器這邊先測驗長度,再去讀取。
uj5u.com熱心網友回復:
你可以先發長度值,再發buffer.uj5u.com熱心網友回復:
這么別扭,客戶端不管這么多,他是發不定長度的報文uj5u.com熱心網友回復:
可以這樣,資料包分兩部分,先發資料包型別,再發資料包內容每次讀的時候,根據包的型別,來讀包的長度
uj5u.com熱心網友回復:
俺不敢再熱情了,是俺傻?俺提出的測驗方案,他都不敢試。。也不敢去思考。
uj5u.com熱心網友回復:
要是都是我自己編程也就簡單了,現在人家有現成的程式,就是不定長度的發和收的,wylton沒有關系,你已經幫我很多了,哥們感謝你給我那些思路
shuihan20e有什么具體代碼可以貼一點吧
uj5u.com熱心網友回復:
請問樓主能否把你服務端和客戶端的代碼發送給我啊,我是學生,正在自學delphi里服務端和客戶端之間通信的內容,苦于找不到好的例程,連那幾個控制元件如何設定都不會,不管怎樣,謝謝了[email protected]
uj5u.com熱心網友回復:
我今天也遇到你一樣的問題我看了一下原始碼
TIdTCPClient在讀取之前加一句FIdTCPClient.IOHandler.CheckForDataOnSource;就可以了
FIdTCPClient.IOHandler.CheckForDataOnSource;
if not FOwner.FIdTCPClient.IOHandler.InputBufferIsEmpty then
begin
FIdTCPClient.IOHandler.ReadBytes(buffer,FIdTCPClient.IOHandler.InputBuffer.Size, False);
BytesToRaw(buffer, FOwner.ReceiveBuffer, Length(buffer));
end;
我用的delphi2007,我想xe應該也差不多
uj5u.com熱心網友回復:
idtcpclient是客戶端組件,不能監聽轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/151839.html
標籤:網絡通信/分布式開發
