![](/img/trans.png)
[英]How to set up a simple connection between TIdTcpClient and TIdTcpServer to send a string from client to server?
[英]TIdTCPServer not able to send data after re-connection of client
我在我的應用程序中使用TIdTCPServer。 在這里,硬件充當tcp客戶端。 客戶端使用SYN命令建立連接(在“工具鯊魚”中可以看到)。 我的應用程序有多個客戶端,因此每個客戶端都連接到我的服務器。 對於第一次連接,數據發送和接收都很好。 但是,當發生硬件電源開和關時,我的服務器無法將數據發送到硬件,直到應用程序重新啟動。 以下是對此的觀察:
1,當客戶端第一次連接到SYN = 0的SYN時,從服務器向客戶端發送Seq = 1的SYN ACK
2.數據收發正常
3.硬件斷電發生
4.在命令提示符下,通過使用“ netstat”,我觀察到已建立斷開的IP和端口號的連接。
5.我發送一些數據(在鯊魚中它顯示了6次重發)
6.此后在“命令提示符”中對應的連接建立的數據沒有出現
7.我現在將數據發送到客戶端,由IdTCPServer引發“連接已關閉”異常(此異常發生后,除了,我使用代碼中的connection.disconnect關閉了連接,並從IdTCPServer的鎖定列表中刪除了該特定客戶端。)
8,硬件上電並發送SYN且Seq No = 0
9.在線鯊魚SYN ACK中將Seq No之類的45678452發送給硬件
10.之后,在命令提示符下觀察到連接建立
11.我嘗試將數據發送到客戶端,但是“ Locklist”沒有再次使用客戶端IP和端口進行更新,因此數據沒有發送給客戶端(我的代碼就像如果IP在“ Locklist”中不存在,那么就不發送數據)。 有什么解決辦法嗎?
以下是我的代碼:
try
for Count := 0 to frmtcpserver.IdTCPServer1.Contexts.LockList.Count - 1
do
begin
if TIdContext(frmtcpserver.IdTCPServer1.Contexts.LockList.Items[Count]).Binding.PeerIP = Destination_IP then
begin
DestinationIPIdx := Count;
end;
end;
frmtcpserver.IdTCPServer1.Contexts.UnlockList;
if DestinationIPIdx > -1 then
begin
// sending data here
TIdContext(frmtcpserver.IdTCPServer1.Contexts.LockList.Items[DestinationIPIdx])
.Connection.IOHandler.Write(TempBuf, NoofBytesToSend,0);
end;
end;
on E: EidException do
begin
TIdContext(frmtcpserver.IdTCPServer1.Contexts.LockList.Items[DestinationIPIdx]).Connection.Disconnect;
frmtcpserver.IdTCPServer1.Contexts.LockList.Delete(DestinationIPIdx);
end;
您多次調用Contexts.LockList()
。 上下文列表受關鍵部分保護。 對LockList()
和UnlockList()
的調用必須保持平衡,否則您將使服務器死鎖,從而阻止客戶端連接和斷開連接。
LockList()
返回實際列表。 因此,您應該將其鎖定一次 ,根據需要訪問其項目,然后將其解鎖一次 。
嘗試類似這樣的方法:
list := frmtcpserver.IdTCPServer1.Contexts.LockList;
try
for i := 0 to list.Count - 1 do
begin
ctx := TIdContext(list[i]);
if ctx.Binding.PeerIP = Destination_IP then
begin
// sending data here
try
ctx.Connection.IOHandler.Write(TempBuf, NoofBytesToSend, 0);
except
on E: EIdException do
begin
ctx.Connection.Disconnect;
end;
end;
break;
end;
end;
finally
frmtcpserver.IdTCPServer1.Contexts.UnlockList;
end;
話雖如此,如果服務器的OnExecute
事件正在與客戶端進行來回通信,那么像您所做的OnExecute
,通常通常不安全地直接從客戶端的OnExecute
事件之外向客戶端發送數據。 您有破壞通訊的風險。 為每個客戶端上下文提供其自己的線程安全的傳出數據隊列,然后在OnExecute
下使用OnExecute
事件發送該數據,這是更安全的方法。 例如:
type
TMyContext = class(TIdServerContext)
public
Queue: TThreadList;
...
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); override;
destructor Destroy; override;
end;
PIdBytes := ^TIdBytes;
constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil);
begin
inherited;
Queue := TThreadList.Create;
end;
destructor TMyContext.Destroy;
var
list: TList;
I: integer;
begin
list := Queue.LockList;
try
for i := 0 to list.Count-1 do
begin
PIdBytes(list[i])^ := nil;
Dispose(list[i]);
end;
finally
Queue.UnlockList;
end;
Queue.Free;
inherited;
end;
procedure TFrmTcpServer.FormCreate(Sender: TObject);
begin
IdTCPServer1.ContextClass := TMyContext;
end;
procedure TFrmTcpServer.IdTCPServer1Execute(AContext: TIdContext);
var
Queue: TList;
tmpList: TList;
i: integer;
begin
...
tmpList := nil;
try
Queue := TMyContext(AContext).Queue.LockList;
try
if Queue.Count > 0 then
begin
tmpList := TList.Create;
tmpList.Assign(Queue);
Queue.Clear;
end;
finally
TMyContext(AContext).Queue.UnlockList;
end;
if tmpList <> nil then
begin
for i := 0 to tmpList.Count-1 do
begin
AContext.Connection.IOHandler.Write(PIdBytes(tmpList[i])^);
end;
end;
finally
if tmpList <> nil then
begin
for i := 0 to tmpList.Count-1 do
begin
PIdBytes(tmpList[i])^ := nil;
Dispose(tmpList[i]);
end;
end;
tmpList.Free;
end;
...
end;
var
list: TList;
ctx: TIdContext;
I: integer;
data: PIdBytes;
begin
list := IdTCPServer1.Contexts.LockList;
try
for i := 0 to list.Count - 1 do
begin
ctx := TIdContext(list[i]);
if ctx.Binding.PeerIP = Destination_IP then
begin
New(data);
try
data^ := Copy(TempBuf, 0, NoofBytesToSend);
TMyContext(ctx).Queue.Add(data);
except
data^ := nil;
Dispose(data);
end;
break;
end;
end;
end;
finally
IdTCPServer1.Contexts.UnlockList;
end;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.