Я настраиваю новую систему, используя Indy 10.6 tcpserver на Raspberry PI с последней загруженной версией Raspbian. Я запускаю приложение с рабочего стола с графическим интерфейсом через скрипт терминала bash с помощью sudo. Все работает нормально, пока клиент не подключится, затем, когда он отключается, я получаю Gtk-WARNINGs, а иногда Gtk-CRITICALs, и я не знаю, почему. Вот мой код, он разрешает только одно клиентское соединение за раз, затем деактивирует сервер и перезапускает его после каждого соединения:
Procedure TFK20Elevator.ASpeedBtn1Click(Sender: TObject);
Begin //start the server
Server.Active := False;
Server.Bindings.Clear;
Server.Bindings.Add.IPVersion := Id_IPv4;
Server.Bindings.Add.IP := LIP;
Server.Bindings.Add.Port := DefPort + StrToIntDef(UnitID, 0);
Try
Server.Active := True;
Except
On E: Exception Do
Memo1.Lines.Add(E.Message);
End;
If Not Server.Active Then
Exit;
ASpeedBtn1.Enabled := False;
ASpeedBtn2.Enabled := True;
AStatus1.SimpleText := 'Server bound to ' + LIP + ':' + IntToStr(DefPort + StrToIntDef(UnitID, 0));
End;
Procedure TFK20Elevator.ServerConnect(AContext: TIdContext);
Begin
If Connected Then
Begin
Abort();
Exit;
End;
AStatus1.SimpleText := 'Connecting to> ' + AContext.Binding.PeerIP + ' - Authenticating...';
Memo1.Lines.Clear;
Manager := False;
EncDecSIdx := 1;
RetryTimer.Enabled := False;
RetryTimer.Interval := 3000;
Authenticating := True;
AuthTimer.Enabled := True;
StayAlive.Enabled := True;
End;
Procedure TFK20Elevator.ServerException(AContext: TIdContext; AException: Exception);
Begin
If AnsiContainsText(AException.Message, 'Gracefully') Then
AStatus1.SimpleText := 'Server bound to ' + LIP + ':' + IntToStr(DefPort + StrToIntDef(UnitID, 0)) //closed gracefully message
Else
Begin //show the exception
Memo1.Lines.Add('An exception happend! - ' + AException.Message);
RetryTimer.Enabled := True;
End;
Manager := False;
Authenticating := False;
End;
Procedure TFK20Elevator.ServerExecute(AContext: TIdContext);
//EncStr and DecStr simply encode/decode, respectively, a standard
// string into/from a key encrypted hex string, i.e. '00' to 'FF'
// for each character in the string
Var
S, UserName, Password: String;
I, N: Integer;
Begin
S := AContext.Connection.IOHandler.ReadLn(IndyTextEncoding_OSDefault, IndyTextEncoding_OSDefault); //get the data
If S = Heart Then //if message is the client heart beat, return to client
Begin //just a heart beat, reset timer
StayAlive.Enabled := False;
AContext.Connection.IOHandler.WriteLn(Heart, IndyTextEncoding_OSDefault, IndyTextEncoding_OSDefault);
StayAlive.Enabled := True;
Exit;
End;
S := PCommon.DecStr(S, EncDecStr, EncDecSIdx); //not heart beat, decompress
If Authenticating Then
Begin //test log in
If Length(S) > 3 Then
Begin
I := Pos('|', S);
If (I > 1) And (Length(S) > I) Then
Begin
UserName := Copy(S, 1, I - 1);
Password := Copy(S, I + 1, Length(S) - I);
If UserName = ManUser Then
Begin
If Password = ManPass Then
Begin
AuthTimer.Enabled := False;
Manager := True;
Authenticating := False;
AContext.Connection.IOHandler.WriteLn(EncStr(AContext.Binding.PeerIP +
':' + IntToStr(DefPort + StrToIntDef(UnitID, 0)) + 'M',
EncDecStr, EncDecSIdx), IndyTextEncoding_OSDefault,
IndyTextEncoding_OSDefault);
AStatus1.SimpleText := 'Connecting to> ' + AContext.Binding.PeerIP + ' as Manager';
Connected := True;
End
Else
AuthTimerTimer(Self);
End
Else If UserName = GenUser Then
Begin
If Password = GenPass Then
Begin
AuthTimer.Enabled := False;
Authenticating := False;
AContext.Connection.IOHandler.WriteLn(EncStr(AContext.Binding.PeerIP +
':' + IntToStr(DefPort + StrToIntDef(UnitID, 0)) + 'U',
EncDecStr, EncDecSIdx), IndyTextEncoding_OSDefault,
IndyTextEncoding_OSDefault);
AStatus1.SimpleText := 'Connecting to> ' + AContext.Binding.PeerIP + ' as General User';
Connected := True;
End
Else
AuthTimerTimer(Self);
End
Else
AuthTimerTimer(Self);
End
Else
AuthTimerTimer(Self);
End
Else
AuthTimerTimer(Self);
End
Else
Begin //test for commands
If Copy(S, 1, Length(AssignID)) = AssignID Then
Begin //command to assign a new unit id
NewLoc := DefLocation;
NewUnit := DefUnitNum;
I := Pos('-', S, 1);
If (I > 0) And (I < Length(S)) Then
Begin
N := Pos('-', S, I + 1);
If (N > 0) And (N < Length(S)) Then
Begin
NewLoc := Copy(S, I + 1, N - I - 1);
NewUnit := Copy(S, N + 1, Length(S) - N);
End;
End;
Label15.Caption := NewLoc;
Label16.Caption := NewUnit;
FmtStr(LIP, '%.3d', [StrToInt(NewUnit)]);
LIP := '192.168.6' + Copy(LIP, 1, 1) + '.' + Copy(LIP, 2, 2); //wifi ip
Memo1.Lines.Add('--> ' + S + '-' + LIP);
AContext.Connection.IOHandler.WriteLn(PCommon.EncStr(Rebooting, EncDecStr, EncDecSIdx),
IndyTextEncoding_OSDefault, IndyTextEncoding_OSDefault);
Memo1.Lines.Add('<-- ' + Rebooting);
TestTimer.Enabled := True;
End;
End;
End;
Procedure TFK20Elevator.ASpeedBtn2Click(Sender: TObject);
Begin //shut down the server with optional restart if not rebooting
AuthTimer.Enabled := False;
RetryTimer.Enabled := False;
StayAlive.Enabled := False;
TestTimer.Enabled := False;
DropClient;
Try
Server.Active := False;
Except
On E: Exception Do
Memo1.Lines.Add('Error disconnecting server - ' + E.Message);
End;
If Server.Active Then
Exit;
ASpeedBtn1.Enabled := True;
ASpeedBtn2.Enabled := False;
AStatus1.SimpleText := 'Server not running...';
Manager := False;
Authenticating := False;
Connected := False;
RetryTimer.Enabled := Not SysReboot;
End;
Procedure TFK20Elevator.ServerDisconnect(AContext: TIdContext);
Begin
StayAlive.Enabled := False;
RetryTimer.Enabled := False;
DropClient;
AStatus1.SimpleText := 'Client disconnected...';
Manager := False;
Authenticating := False;
Connected := False;
RetryTimer.Enabled := Not SysReboot;
End;
Procedure TFK20Elevator.DropClient; //make sure buffers are cleared
Var
I: Integer;
SC: TIdContext;
Begin
If Server.Active Then
Begin
Application.ProcessMessages;
With Server.Contexts.LockList Do
Try
Memo1.Lines.Add('Disconnecting...');
For I := Count - 1 DownTo 0 Do
Begin
SC := TIdContext(Items[I]);
If SC = Nil Then
Continue;
SC.Connection.IOHandler.WriteBufferClear;
SC.Connection.IOHandler.InputBuffer.Clear;
SC.Connection.IOHandler.Close;
If SC.Connection.Connected Then
SC.Connection.Disconnect;
Memo1.Lines.Add('Disconnecting client ' + IntToStr(I + 1) + ' of ' + IntToStr(Count));
End;
Finally
Server.Contexts.UnlockList;
Memo1.Lines.Add('Disconnected');
End;
End;
End;
Procedure TFK20Elevator.StayAliveTimer(Sender: TObject);
Begin //server reset timer if client stops sending heart beat
StayAlive.Enabled := False;
AStatus1.SimpleText := 'Client timed out!';
If ASpeedBtn2.Enabled Then
ASpeedBtn2Click(Self);
End;
Procedure TFK20Elevator.AuthTimerTimer(Sender: TObject);
Begin //login authorization timeout timer
AuthTimer.Enabled := False;
ASpeedBtn2Click(Self);
Application.ProcessMessages;
ASpeedBtn1Click(Self);
End;
TIdTCPServer
на самом деле не предназначен для использования таким образом. Если вы хотите, чтобы одновременно подключался только один клиент, установите для свойстваTIdTCPServer.MaxConnections
значение 1 или рассмотрите возможность использования вместо негоTIdSimpleServer
. - person Remy Lebeau   schedule 27.01.2017TIdTCPConnection
с добавленными(Begin)Listen()
методами. ВызовитеListen()
, чтобы дождаться подключения клиента, а затем при необходимости используйте унаследованныеTIdTCPConnection
свойства/методы. В отличие отTIdTCPServer
,TIdSimpleServer
не является многопоточным, поэтому вам придется запускать его в своем собственном потоке. Но это делает одноклиентские серверы намного проще в использовании, чемTIdTCPServer
. - person Remy Lebeau   schedule 27.01.2017