TIdTCPServer无法在客户端重新连接后发送数据
我在我的应用程序中使用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;
要调用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;
按照您的建议更改代码(仅访问锁定列表一次),工作正常。谢谢您的回答。 –
你都清楚地在服务器端错误地管理客户端(!例如,不要手动删除服务器内部列表条目,不吞例外),但因为你没有显示任何你的实际代码,所以没有人能告诉你你做错了什么或者如何解决它。请显示您的实际代码。 –
即使我不从列表中删除TIdTCPServer也无法在重新连接后发送数据。 –