IdTCPServer1Execute catch

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

IdTCPServer1Execute catch

Postby Lena » Fri Mar 13, 2015 6:24 am

Code: Select all
class TUpdateRichEdit : public TIdSync
{
   protected:
   String sText;
   void __fastcall DoSynchronize();
   public:
   __fastcall TUpdateRichEdit( const String &sMessage );

};


Code: Select all
String GenerateAlphaNumStr_N(size_t n)
{
    static char randommmm[] =
    {
      'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 'A', 'S', 'D', 'F', 'G',
      'H', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '1', '2', '3', '4',
        '5', '6', '7', '8', '9', '0'
    };

   String result;
   for(size_t i = 0; i < n; ++i)
      result+= randommmm[random(sizeof(randommmm))];

      String s = (String)"{\"server\":\"pascal\",\"time\":";
      time_t t;
      t = time(NULL);
      s += IntToStr((__int64)t)+(String)",\"salt\":\"";
      s += result + "\"}\n";

   return s;
}

//---------------------------------------------------------------------------
void ZapisVRichEditWindow(String zapis)
{
  TUpdateRichEdit *updateLB = new TUpdateRichEdit(zapis);
  try
   {
    updateLB->Synchronize();
   }
      __finally
      {
       delete updateLB;
      }
}

//---------------------------------------------------------------------------
__fastcall TUpdateRichEdit::TUpdateRichEdit( const String &sMessage ): TIdSync()
{
   sText = sMessage;
}

//---------------------------------------------------------------------------
void __fastcall TUpdateRichEdit::DoSynchronize()
{
  Form1Main->RichEditProtocol->Lines->Add(sText);
}
//---------------------------------------------------------------------------

void __fastcall TForm1Main::FormClose(TObject *Sender, TCloseAction &Action)
{
 ServerContainer1->DSServer1->Stop();
 IdTCPServer1->Active = false;
}

//---------------------------------------------------------------------------
void __fastcall TForm1Main::FormCreate(TObject *Sender)
{
 IdTCPServer1->Active = true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1Main::IdTCPServer1Execute(TIdContext *AContext)
{
  try
    {
        //post a reply
        String Otvet = GenerateAlphaNumStr_N(32);
        AContext->Connection->IOHandler->WriteLn(Otvet);

        //receiving data
        String Sdata = AContext->Connection->IOHandler->ReadLn();
        ZapisVRichEditWindow(Sdata);
     }
    catch (const EIdNotConnected&)
       {
       throw;
      }
    catch (const EIdClosedSocket&)
       {
       throw;
       }
    catch (EIdConnClosedGracefully&)
       {
       throw;
      }
    catch (const Exception &E)
       {
        String mis = L"Mistake. Class: " + E.ClassName() + L" Message: " +  E.Message;
        ShowMessage(mis);
        if (dynamic_cast<const EIdException*>(&E) != NULL)
             throw;
       }
}

//---------------------------------------------------------------------------
void __fastcall TForm1Main::IdTCPServer1Connect(TIdContext *AContext)
{
  String ConnectServer = L"Connect: " +
                    AContext->Connection->Socket->Binding->PeerIP;
  ZapisVRichEditWindow(ConnectServer);
}

//---------------------------------------------------------------------------
void __fastcall TForm1Main::IdTCPServer1Disconnect(TIdContext *AContext)
{
 String DisconnectServer = L"Disconnet: " +
                    AContext->Connection->Socket->Binding->PeerIP;
 ZapisVRichEditWindow(DisconnectServer);
}


The device sends data. I see it in RichEdit. It's okay.
When I try to close the main window of the program is not responding.
In debug mode I see error EidNotConnected Not Connected. How to correctly catch this situation?
How I can close main window of my programm?
Lena
BCBJ Master
BCBJ Master
 
Posts: 583
Joined: Sun Feb 06, 2011 1:28 pm

Re: IdTCPServer1Execute catch

Postby Lena » Fri Mar 13, 2015 6:58 am

If I comment IdTCPServer1Disconnect I can close main form. But I need code in IdTCPServer1Disconnect :(
Code: Select all
void __fastcall TForm1Main::IdTCPServer1Disconnect(TIdContext *AContext)
{
 /*
 String DisconnectServer = L"Disconnect: " +
                  AContext->Connection->Socket->Binding->PeerIP;
 ZapisVRichEditWindow(DisconnectServer);
 */
}
Lena
BCBJ Master
BCBJ Master
 
Posts: 583
Joined: Sun Feb 06, 2011 1:28 pm

Re: IdTCPServer1Execute catch

Postby Lena » Sat Mar 14, 2015 8:20 am

I think I solved the problem. I should add this code:
Code: Select all
 void __fastcall TForm1Main::FormClose(TObject *Sender, TCloseAction &Action)
{

 try
   {
    TList *Lst = IdTCPServer1->Contexts->LockList();
    for(int i = 0; i < Lst->Count; i++)
      {
        TIdContext *AContext = reinterpret_cast<TIdContext *>(Lst->Items[i]);
        AContext->Connection->Disconnect();
      }
   }
   __finally
         {
           IdTCPServer1->Contexts->UnlockList();
         }

 IdTCPServer1->Active = false;
 ServerContainer1->DSServer1->Stop();
}


Maybe there are other remarks in my code all over?
Lena
BCBJ Master
BCBJ Master
 
Posts: 583
Joined: Sun Feb 06, 2011 1:28 pm

Re: IdTCPServer1Execute catch

Postby rlebeau » Mon Mar 16, 2015 6:13 pm

Lena wrote:When I try to close the main window of the program is not responding.


When TIdTCPServer is deactivating, it closes its active sockets and waits for its active client threads to terminate. The thread that is deactivating TIdTCPServer is blocked until deactivation is finished.

When you call TIdSync::Synchronize(), the calling thread is blocked until the main UI thread is finished processing the request.

If you deactivate TIdTCPServer in the main UI thread, calling TIdSync::Synchronize() while the main UI thread is blocked will deadlock everything - the main UI thread is blocked waiting for TIdTCPServer to deactivate (OK), TIdTCPServer is blocked waiting for client threads to terminate (OK), client threads are blocked waiting for TIdSync::Synchronize() to exit (OK), and TIdSync is blocked waiting for the main UI thread to process the request (deadlock!).

Lena wrote:In debug mode I see error EidNotConnected Not Connected. How to correctly catch this situation?


You don't need to, nor should you be trying to. In fact, most of your catch statements are redundant and should be removed from the code completely.

Lena wrote:How I can close main window of my programm?


You have a few choices.

1. stop calling TIdSync::Synchronize() while TIdTCPServer is deactivating.

2. deactivate TIdTCPServer from a worker thread so the main UI can process TIdSync requests.

3. switch to TIdNotify, as your client code is not dependent on getting any results from the main UI thread, so using TIdSync is overkill in your example.

I would suggest #3. Try this:

Code: Select all
class TUpdateRichEdit : public TIdNotify
{
protected:
    String sText;
    void __fastcall DoNotify();
public:
    __fastcall TUpdateRichEdit( const String &sMessage );
};

String GenerateAlphaNumStr_N(size_t n)
{
    static char randommmm[] =
    {
      'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 'A', 'S', 'D', 'F', 'G',
      'H', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '1', '2', '3', '4',
        '5', '6', '7', '8', '9', '0'
    };

    String result;
    for(size_t i = 0; i < n; ++i)
      result += randommmm[random(sizeof(randommmm)/sizeof(randommmm[0]))];

    time_t t;
    t = time(NULL);

    String s = L"{\"server\":\"pascal\",\"time\":";
    s += IntToStr((__int64)t) + L",\"salt\":\"";
    s += result + L"\"}\n";

    return s;
}

//---------------------------------------------------------------------------
void ZapisVRichEditWindow(String zapis)
{
    TUpdateRichEdit *updateLB = new TUpdateRichEdit(zapis);
    try
    {
        updateLB->Notify();
    }
    catch (const Exception &)
    {
        delete updateLB;
        throw;
    }
}

//---------------------------------------------------------------------------
__fastcall TUpdateRichEdit::TUpdateRichEdit( const String &sMessage )
    : TIdNotify(), sText(sMessage)
{
}

//---------------------------------------------------------------------------
void __fastcall TUpdateRichEdit::DoNotify()
{
    if ((Form1Main) && (Form1Main->RichEditProtocol))
        Form1Main->RichEditProtocol->Lines->Add(sText);
}
//---------------------------------------------------------------------------

void __fastcall TForm1Main::FormClose(TObject *Sender, TCloseAction &Action)
{
    ServerContainer1->DSServer1->Stop();
    IdTCPServer1->Active = false;
}

//---------------------------------------------------------------------------
void __fastcall TForm1Main::FormCreate(TObject *Sender)
{
    IdTCPServer1->Active = true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1Main::IdTCPServer1Execute(TIdContext *AContext)
{
    try
    {
        //post a reply
        String Otvet = GenerateAlphaNumStr_N(32);
        AContext->Connection->IOHandler->WriteLn(Otvet);

        //receiving data
        String Sdata = AContext->Connection->IOHandler->ReadLn();
        ZapisVRichEditWindow(Sdata);
    }
    catch (const EIdNotConnected&)
    {
        throw;
    }
    catch (const EIdClosedSocket&)
    {
        throw;
    }
    catch (const EIdConnClosedGracefully&)
    {
        throw;
    }
    catch (const Exception &E)
    {
        String mis = L"Mistake. Class: " + E.ClassName() + L" Message: " + E.Message;

        // ShowMessage() is not thread-safe!  Do not call it from outside of
        // the main UI thread.  In fact, you really should not be showing a
        // popup message box here at all!
        MessageBoxW(NULL, mis.c_str(), L"", MB_OK | MB_ICONERROR);

        if (dynamic_cast<const EIdException*>(&E) != NULL)
             throw;
    }
}

//---------------------------------------------------------------------------
void __fastcall TForm1Main::IdTCPServer1Connect(TIdContext *AContext)
{
    String ConnectServer = L"Connect: " + AContext->Connection->Socket->Binding->PeerIP;
    ZapisVRichEditWindow(ConnectServer);
}

//---------------------------------------------------------------------------
void __fastcall TForm1Main::IdTCPServer1Disconnect(TIdContext *AContext)
{
    String DisconnectServer = L"Disconnet: " + AContext->Connection->Socket->Binding->PeerIP;
    ZapisVRichEditWindow(DisconnectServer);
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1544
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: IdTCPServer1Execute catch

Postby Lena » Tue Mar 17, 2015 1:21 am

I would suggest #3. Try this:


Thank you!
I just add sText = sMessage in TUpdateRichEdit::TUpdateRichEdit
Code: Select all
__fastcall TUpdateRichEdit::TUpdateRichEdit( const String &sMessage )
    : TIdNotify(), sText(sMessage)
{
 sText = sMessage;
}

//---------------------------------------------------------------------------
void __fastcall TUpdateRichEdit::DoNotify()
{
   if ((Form1Main) && (Form1Main->RichEditProtocol) && (sText[1] != '$'))
      Form1Main->RichEditProtocol->Lines->Add(sText);

   else if ((Form1Main) && (Form1Main->ListBox1) && (sText[1] == '$'))
         {
          sText.Delete(1,1);
          Form1Main->ListBox1->Items->Add(sText); //IP address
         }

}
//---------------------------------------------------------------------------
void ZapisVRichEditWindow(String zapis)
{
   TUpdateRichEdit *updateLB = new TUpdateRichEdit(zapis);
   try
   {
      updateLB->Notify();
   }
   catch (const Exception &)
   {
      delete updateLB;
      throw;
   }
}

void __fastcall TForm1Main::IdTCPServer1Connect(TIdContext *AContext)
{
   String ConnectServer = L"Connect: " +
                  AContext->Connection->Socket->Binding->PeerIP;

   String ConnectClientIP = L"$" + AContext->Connection->Socket->Binding->PeerIP;
   ZapisVRichEditWindow(ConnectClientIP);
   ZapisVRichEditWindow(ConnectServer);
}


TUpdateRichEdit *updateLB = new TUpdateRichEdit(zapis);

1. Is it correct not delete updateLB in ZapisVRichEditWindow?

2. Can leave this code or not in FormClose?
Code: Select all
try
   {
    TList *Lst = IdTCPServer1->Contexts->LockList();
    for(int i = 0; i < Lst->Count; i++)
      {
        TIdContext *AContext = reinterpret_cast<TIdContext *>(Lst->Items[i]);
        AContext->Connection->Disconnect();
      }
   }
   __finally
         {
           IdTCPServer1->Contexts->UnlockList();
         }


P.S.
3.Why growing indicator I/O Other in my code? Is not a problem?
Attachments
1.jpg
1.jpg (40.7 KiB) Viewed 16258 times
Lena
BCBJ Master
BCBJ Master
 
Posts: 583
Joined: Sun Feb 06, 2011 1:28 pm

Re: IdTCPServer1Execute catch

Postby rlebeau » Tue Mar 17, 2015 12:13 pm

Lena wrote:I just add sText = sMessage in TUpdateRichEdit::TUpdateRichEdit


You don't need to do that. That assignment is being handled by the constructor's initialization list (you do know what that is, right?):

Code: Select all
__fastcall TUpdateRichEdit::TUpdateRichEdit( const String &sMessage )
    : TIdNotify(), **sText(sMessage)**
{
}


Lena wrote:
Code: Select all
void __fastcall TUpdateRichEdit::DoNotify()
{
   if ((Form1Main) && (Form1Main->RichEditProtocol) && (sText[1] != '$'))
      Form1Main->RichEditProtocol->Lines->Add(sText);

   else if ((Form1Main) && (Form1Main->ListBox1) && (sText[1] == '$'))
         {
          sText.Delete(1,1);
          Form1Main->ListBox1->Items->Add(sText); //IP address
         }

}



I would suggest re-coding that to something more like this:

Code: Select all
#include <StrUtils.hpp>

void __fastcall TUpdateRichEdit::DoNotify()
{
    if (sText.IsEmpty()) return;
    if (sText[1] != '$')
    {
        if ((Form1Main) && (Form1Main->RichEditProtocol))
            Form1Main->RichEditProtocol->Lines->Add(sText);
    }
    else
    {
        if ((Form1Main) && (Form1Main->ListBox1))
            Form1Main->ListBox1->Items->Add(sText.SubString(2, MaxInt)); //IP address
    }
}


Lena wrote:TUpdateRichEdit *updateLB = new TUpdateRichEdit(zapis);

1. Is it correct not delete updateLB in ZapisVRichEditWindow?


Yes, because TIdNotify::Notify() is asynchronous. It puts the TIdNotify object into a queue and returns immediately, so you cannot 'delete' the object right away. It will free itself automatically at a later time once it has been retrieved from the queue and its DoNotify() method has run.

Lena wrote:2. Can leave this code or not in FormClose?


I suggest you remove it. It is redundant code. TIdTCPServer already does that logic internally when you deactivate/free it. If you want on OnClose handler, then you should just deactivate the server instead:

Code: Select all
void __fastcall TForm1Main::FormClose(TObjct *Sender, TCloseAction &Action)
{
    IdTCPServer1->Active = false;
}


Lena wrote:P.S.
3.Why growing indicator I/O Other in my code? Is not a problem?


I do not understand what you are asking. What is the highlighted number representing?
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1544
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: IdTCPServer1Execute catch

Postby Lena » Wed Mar 18, 2015 1:05 am

Thank you very much for your help!

I do not understand what you are asking. What is the highlighted number representing?


I add new picture. Scroll down the picture and there you will see growth.
Attachments
task.gif
task.gif (140.07 KiB) Viewed 16227 times
Lena
BCBJ Master
BCBJ Master
 
Posts: 583
Joined: Sun Feb 06, 2011 1:28 pm

Re: IdTCPServer1Execute catch

Postby rlebeau » Wed Mar 18, 2015 1:42 am

Lena wrote:I add new picture. Scroll down the picture and there you will see growth.


Your code is continuously sending/receiving data over sockets. The number you have highlighted in Task Manager is counting I/O operations. What is the problem?
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1544
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: IdTCPServer1Execute catch

Postby Lena » Wed Mar 18, 2015 1:46 am

Now there are no problems after your explanation. Thank you very much!
Lena
BCBJ Master
BCBJ Master
 
Posts: 583
Joined: Sun Feb 06, 2011 1:28 pm


Return to Technical

Who is online

Users browsing this forum: Bing [Bot] and 3 guests

cron