我使用了多端口TCP服务器来接收一些连接
像这样
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var
aByte: Byte;
i,j , tmBodyFrameLength:integer;
myThread : tthread;
begin
if not Assigned( allOfflineStringList ) then
begin
allOfflineStringList := TStringlist.Create;
end;
allOfflineStringList.Clear;
case AContext.Binding.Port of
55000: begin {offline and image}
AContext.Connection.IOHandler.ReadBytes(data, 1099, False);
rowFrame :='';
for I := 0 to length(data)-1 do
begin
rowFrame := rowFrame + (data[i].ToHexString);
end;
newFrame := copy( rowFrame , 9 , maxInt );
allOfflineStringList.Append( newFrame );
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
Label985.caption := 'Offline : ' + allOfflineStringList.Count.ToString ;
//Memo14.Lines.Add( datetimetostr(now) +':'+ newFrame );
form2.AbLED601.Tag := DateTimeToUnix(now);
form2.AbLED601.Checked := true;
end);
end;
55001: begin {tm online}
repeat
aByte := AContext.Connection.IOHandler.ReadByte;
if aByte=$C0 then
begin
SDRtmOnlineRowFrame2 := SDRtmOnlineRowFrame;
SDRtmOnlineRowFrame := '';
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
form2.Memo14.Lines.Add('tm:'+ SDRtmOnlineRowFrame2 );
end);
end
else
begin
SDRtmOnlineRowFrame := SDRtmOnlineRowFrame + aByte.ToHexString;
end;
until true;
end;
55003: begin {beacon online}
repeat
aByte := AContext.Connection.IOHandler.ReadByte;
if aByte=$C0 then
begin
SDRtmOnlineBeaconRowFrame2 := SDRtmOnlineBeaconRowFrame;
SDRtmOnlineBeaconRowFrame := '';
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
form2.Memo14.Lines.Add('beacon:'+ SDRtmOnlineBeaconRowFrame2 );
end);
end
else
begin
SDRtmOnlineBeaconRowFrame := SDRtmOnlineBeaconRowFrame + aByte.ToHexString;
end;
until true;
end;
end;
end;
一切正常,但是当我关闭连接时正在接收数据
应用程序将停止通话,并且不再响应!
启用和禁用是这样的:
procedure TForm2.CheckBox6Click(Sender: TObject);
var
ic:integer;
allIpList : TStringList;
begin
AbLED412.Checked := CheckBox6.Checked;
if CheckBox6.Checked=true then
begin
IdTCPServer1.Active := False;
IdTCPServer1.Bindings.Clear;
with IdTCPServer1.Bindings.Add do
begin
//IP := '192.168.1.5';
Port := 55000;
end;
with IdTCPServer1.Bindings.Add do
begin
//IP := '192.168.1.5';
Port := 55001;
end;
with IdTCPServer1.Bindings.Add do
begin
//IP := '192.168.1.5';
Port := 55003;
end;
IdTCPServer1.Active := True;
IdTCPServer1.StartListening;
TIdStack.IncUsage;
try
allIpList := TStringList.Create;
GStack.AddLocalAddressesToList( allIpList );
memo14.lines.clear;
for ic := 0 to allIpList.Count-1 do
begin
memo14.lines.Add('Create tcp connection on ip : '+allIpList[ic]+' and port : 55000');
memo14.lines.Add('Create tcp connection on ip : '+allIpList[ic]+' and port : 55001');
memo14.lines.Add('Create tcp connection on ip : '+allIpList[ic]+' and port : 55003');
end;
finally
TIdStack.DecUsage;
end;
end
else
begin
IdTCPServer1.StopListening;
IdTCPServer1.Active := False;
IdTCPServer1.Bindings.Clear;
memo14.lines.clear;
end;
end;
当我关闭应用程序时也接收到数据时再次挂起,但发件人断开连接时关闭应用程序也不会造成任何问题
我怎样才能解决这个问题?
您的TIdTCPServer.OnExecute
处理程序以线程不安全的方式使用多个变量。您不能保护它们免受同时访问它们的多个线程的影响,从而导致它们的数据出现争用情况。
但是,更重要的是,您使用TThread.Synchronize()
死锁是一个常见的死锁原因,TIdTCPServer
因为死锁是一个多线程组件。其OnConnect
,OnDisconnect
,OnExecute
,和OnError
事件被称为客户端工作线程的背景下,而不是在主UI线程。TThread.Synchronize()
阻塞调用线程,直到主UI线程处理请求为止。停用将TIdTCPServer
终止所有正在运行的客户端线程,并等待它们完全终止。因此,如果TThread.Synchronize()
在阻止主UI线程停用服务器的同时调用客户端线程,则客户端线程正在主UI线程上等待,而主UI线程正在客户端线程上等待-死锁!
您可以通过以下几种方法解决此问题:
避免TThread.Synchronize()
在停用服务器时调用。说起来容易做起来难,因为在TThread.Synchronize()
您决定停用时,您可能已经处于待处理状态TIdTCPServer
。并且在决定是否打电话时是一个竞赛条件TThread.Synchronize()
。
TIdTCPServer
在单独的工作线程中停用,使主UI线程可以自由处理TThread.Synchronize()
和TThread.Queue()
请求。如果您使用aTThread
进行停用,则TThread.WaitFor()
在等待线程终止时,在主UI线程中调用方法将处理Synchronize()
/Queue()
请求。
使用TThread.Queue()
代替TThread.Synchronize()
,尤其是在执行客户端线程实际上不需要等待的操作(例如UI更新)时。
另外,在您的中CheckBox6Click()
:
你不应该打电话TIdTCPServer.StartListening()
或TIdTCPServer.StopListening()
在所有。该TIdTCPServer.Active
属性setter调用它们内部的你。
您不需要调用TIdStack.IncUsage()
或TIdStack.DecUsage()
,因为TIdTCPServer
的构造函数和析构函数会为您调用它们。
你在漏水allIpList
,不是Free()
。并且TIdStack.AddLocalAddressesToList()
无论如何都已弃用,您应该TIdStack.GetLocalAddressList()
改为使用。
尝试这个:
procedure TForm2.CheckBox6Click(Sender: TObject);
var
ic: integer;
allIpList : TIdStackLocalAddressList;
begin
AbLED412.Checked := CheckBox6.Checked;
if CheckBox6.Checked then
begin
IdTCPServer1.Active := False;
IdTCPServer1.Bindings.Clear;
with IdTCPServer1.Bindings.Add do
begin
//IP := '192.168.1.5';
Port := 55000;
end;
with IdTCPServer1.Bindings.Add do
begin
//IP := '192.168.1.5';
Port := 55001;
end;
with IdTCPServer1.Bindings.Add do
begin
//IP := '192.168.1.5';
Port := 55003;
end;
IdTCPServer1.Active := True;
allIpList := TIdStackLocalAddressList.Create;
try
GStack.GetLocalAddressesList( allIpList );
Memo14.Lines.Clear;
{
for ic := 0 to IdTCPServer1.Bindings.Count-1 do
begin
Memo14.Lines.Add('Create tcp connection on ip : ' + IdTCPServer1.Bindings[ic].IP + ' and port : ' + IntToStr(IdTCPServer1.Bindings[ic].Port));
end;
}
for ic := 0 to allIpList.Count-1 do
begin
if allIpList[ic].IPVersion = ID_DEFAULT_IP_VERSION then
begin
Memo14.Lines.Add('Create tcp connection on ip : ' + allIpList[ic].IPAddress + ' and port : 55000');
Memo14.Lines.Add('Create tcp connection on ip : ' + allIpList[ic].IPAddress + ' and port : 55001');
Memo14.Lines.Add('Create tcp connection on ip : ' + allIpList[ic].IPAddress + ' and port : 55003');
end;
end;
finally
allIpList.Free;
end;
end
else
begin
IdTCPServer1.Active := False;
IdTCPServer1.Bindings.Clear;
Memo14.Lines.Clear;
end;
end;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句