2017-07-28 244 views
0

我在我的应用程序中使用TIdTCPServer。这里的硬件充当tcp客户端。客户端使用SYN命令建立连接(在作为工具的线鲨中观察)。我的应用程序有多个客户,所以每个客户都连接到我的服务器对于第一次连接,数据发送&接收是好的。但是当硬件关机&发生时,我的服务器无法将数据发送到硬件,直到应用程序重新启动。以下是关于本的意见:TIdTCPServer无法在客户端重新连接后发送数据

1.当第一次客户机具有SEQ无连接SYN = 0接收的,SYN ACK具有SEQ否= 1名发送到客户端从服务器

2.Data发送&接收是工作正常

3.Hardware断电通过使用“netstat的”我观察到存在用于断开的IP &端口号建立的连接发生

4.In命令提示。

5.I发送一些数据(在电线鲨它显示6次重传)

6.After这在“命令提示”对应连接建立的数据没有出现

7.I将数据发送到客户端现在由IdTCPServer引发的“连接关闭”异常(在此异常之后,除了我通过使用connection.disconnect关闭连接,代码&从IdTCPServer的Locklist中删除了该特定客户端)

8.Hardware powered &发送SYN与Se Q无= 0

9.In丝鲨SYN ACK具有SEQ没有像45678452发送到硬件

10.After,在命令提示连接建立观察

11.I试图将数据发送到客户端,但“锁定列表”没有与客户端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; 
+2

你都清楚地在服务器端错误地管理客户端(!例如,不要手动删除服务器内部列表条目,不吞例外),但因为你没有显示任何你的实际代码,所以没有人能告诉你你做错了什么或者如何解决它。请显示您的实际代码。 –

+0

即使我不从列表中删除TIdTCPServer也无法在重新连接后发送数据。 –

回答

1

要调用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事件,就像你正在做的一样。你冒着破坏通信的风险。给每个客户端上下文自己的线程安全的传出数据队列更安全,然后在安全的情况下使用事件发送该数据。例如:

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; 
+0

按照您的建议更改代码(仅访问锁定列表一次),工作正常。谢谢您的回答。 –

相关问题