How to disconnect to a indy server?

Hi!

I have a server application that from start to the end just sends data and then my client recives the data and plot it.
The problem is that the client should be able to disconnect at any time.
Right now if i disconnect during the sending the server throws a EIdSocketError and i catch it and disconnect,
but the problem is that if i then try to connect to the server again the server throws a EIdSocketError again so the
client cant connect unlees i restart the client application? I think this has to do with that the port number still is occupied.
I nead to know how to handle a "bad" disconnection.

Thanks
mikrodidaktAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

2266180Commented:
Hi mikrodidakt,

that is hard to say without seeing at least how the server and client "protocol" is set up.
so either post you code, or explain your protocol and implementation (if you are using threads, thread pool, etc)

Cheers!
0
atul_parmarCommented:
I suggest,

before desconnecting your client, send a msg from client to the server that it is about to disconnect so that the server could stop sending the data to it can perform any clean ups if required.. Once, it is acknowledged and the cleanup is over, you can disconnect your client.
0
mikrodidaktAuthor Commented:
Hi!

Teh problem is that i dont have the server yet, But the information i got is that the server is just going to start sending the data over ethernet on specific port and my client is going to listen to that port and plot the values.
So i am writing a server that is simulating this.
I have also got it explained that the server will accept a disconnection at any time.
I just want my client to be able to connect again after a "bad disconnection", and i think that the problem is at the client side since it works if I restatart the client? My code is in C++ so if you think it would help I will post it.
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

mikrodidaktAuthor Commented:
By the way i am using the Indy 9 components and there is not that many C++ programmers that is using that so thoubht i would ask my question here instead.
0
mikrodidaktAuthor Commented:
atul_parmar you are talking about clean up, could you explain this clean up because the only clean up i am doing is disconnect?
0
atul_parmarCommented:
I mean the server might expect some termination commands before you disconnect your client. If it is not the case, you can try DisconnectSocket method.

The problem seems that when you try to disconnect, some process is already using the port. it works after restarting the process gets terminated when you close the client.
0
mikrodidaktAuthor Commented:
I have already tryied DisconnectSocket and that did not help.

1)This is how the "protocol" works i start my client and my server.
2)The user click on connect button on the client and the server accepts the connection by sending a reply.
3)The server is starting to send data and the client is reciving the data and ploting it in realtime

At any time during the reciving the user could click on a stop button this stop button is disconnecting the client from the server and this is where i get the problem. I handle the exception that is thrown on the server side and the client side is just disconnecting.
But it should be possible to run step 2 and 3  again at any time after a disconnection. As it is now the client has to be restarted to be able to establish a connection to the server.

Thanks for your help!
0
TheRealLokiSenior DeveloperCommented:
Do _not_ hide the exception...you are meant to let it happen
any unhandled exception in the OnExecute event is caught by indy, which then disconnects the client socket
e.g.
onexecute event...
try
  dostuff
except
  on E: exception do
  begin
      DisplayThisMessageInMyLog;
      RAISE; // this is important
  end;
end;
0
mikrodidaktAuthor Commented:
Ok i understand that the right way to do it is to send a message to the server telling it that now it is time to disconnect and that is fine, but the server that i will be using in the future will not accept a message that like that.
So i just want the client to be able to disconnect and connect in infiniti.
As i see it the client will be able to disconnect but for some reason the port on the client not the server is locked in some way, the reason i think so is that when i start my server (the server i am using is not the server that i will use later is is just a simple server that i have writen to simulate the finnal server) and then disconnect from it with the client i can not connect again without the  EIdSocketError trown. Even if i restart the server the exception is trown untill i restart the client.
0
TheRealLokiSenior DeveloperCommented:
no really... let the exception happen on the server. indy uses exceptions a lot, they are not all meant to be handled by you. They let the server know that it has to disconnect the socket. You do not need to disconnect it manually in the server code.
0
TheRealLokiSenior DeveloperCommented:
on the client, make sure you have NOT set the "boundport" property, only the port property
indy usually lets windows pick the next available port to use, but youcan specifically set it, or use a range with boundportmin and boundportmax

1 other thing, there are several ways to disconnect the socket. eg. for indy's ftp client
on indy 9 you may use
IdFtp1.DisconnectSocket;
on indy 10.0.5.2 you may use
IdFtp1.Socket.Close;
0
mikrodidaktAuthor Commented:
Ok I might not understand you TheRealLoki I did as you wat you wanted i let the exception "happen".
But i still cant reconnect to the server after i have disconnected in a "bad manner", the server just throws a the exception again until i restart my client then i get a connection and the server starts to send the packages.
0
2266180Commented:
why don't you post your code :) I'm sure we can help you faster that way ;)
0
mikrodidaktAuthor Commented:
void __fastcall TForm1::IdTCPServer1Execute(TIdPeerThread *AThread)
{
        try {
                VMes = static_cast<void *>(mes);
                LLine = AThread->Connection->ReadLn();
                LCmd = Fetch(LLine);

               if(AnsiSameText(LCmd, "SEND")) {
                        //----------------------ignore this------------------------
                        mes = (Message*) malloc(sizeof(Message));
                        mes->STX          = 0x0002;
                        mes->CRC          = 0x858E;
                        mes->MachID       = 0x000A;
                        mes->ClinicalSWID = 0x0064;
                        mes->MsgCounter   = 0x00000000;
                        mes->CmdCode      = 0x00000000;
                        mes->MsgInfo      = 0x00000066;
                        mes->Flags        = 0x00000002;
                        mes->PatId        = 0x000004BC;
                        mes->records[0].Param_code    = 0x00000005;
                        mes->records[0].Time          = 0x437CA428;
                        mes->records[0].Measure_Value = 0x000004C8;
                        mes->records[1].Param_code    = 0x00000001;
                        mes->records[1].Time          = 0x437CA428;
                        mes->records[1].Measure_Value = 0xFFFFFFD4;
                        mes->records[2].Param_code    = 0x00000002;
                        mes->records[2].Time          = 0x437CA428;
                        mes->records[2].Measure_Value = 0x00000059;
                        mes->records[3].Param_code    = 0x00000003;
                        mes->records[3].Time          = 0x437CA428;
                        mes->records[3].Measure_Value = 0xFFFFFFFE;
                        mes->records[4].Param_code    = 0x00000004;
                        mes->records[4].Time          = 0x437CA428;
                        mes->records[4].Measure_Value = 0x00000022;
                        mes->records[5].Param_code    = 0x00000005;
                        mes->records[5].Time          = 0x437CA428;
                        mes->records[5].Measure_Value = 0x00000000;
                        mes->records[6].Param_code    = 0x00000006;
                        mes->records[6].Time          = 0x437CA428;
                        mes->records[6].Measure_Value = 0x0000003E;
                        mes->records[7].Param_code    = 0x00000007;
                        mes->records[7].Time          = 0x437CA428;
                        mes->records[7].Measure_Value = 0x0000001F;
                        //-------------------------------------------------------------------
                        int y = 0;
                        while(y < 1000){
                                mes->records[2].Time++;
                                randomize();
                                mes->records[2].Measure_Value = 10*sin((random(100)%10)/3);
                               
                                Idglobal::Sleep(500);
                                ++y;
                                VMes = static_cast<void *>(mes);
                                long int PktSize = sizeof(*mes);
                                AThread->Connection->WriteBuffer(VMes, PktSize);
                        }
                }
        } catch(EIdConnClosedGracefully& e) {
                AThread->Connection->Disconnect();
                Memo1->Lines->Add("Connection Closed");
        }
       /*
       catch(EIdSocketError& e) {
                AThread->Connection->Disconnect();
                Memo1->Lines->Add("Connection Closed");
        }  
       */
}
0
mikrodidaktAuthor Commented:
On the client side

void __fastcall TForm1::ConnectButtonClick(TObject *Sender)
{
        GraphHandler gh(*Series1, *Chart1, *ChartEditor1);
        MessageHandler mh;
        Message* mes;
        void* VMes = (void*) malloc(sizeof(*mes));

        short response = 200;
        bool first_mess = true;
        ConnectButton->Enabled = false;
        lboxResult->Clear();
        this->Series1->Clear();
        try{
            try{
                TCPConn->Connect();
                this->StatusBar1->SimpleText = "  Starting to processing recived data....";
                TCPConn->GetResponse(&response, sizeof(response));
                lboxResult->Items->AddStrings(TCPConn->LastCmdResult->Text);
                lboxResult->Items->Add("");

                TCPConn->WriteLn("SEND");
                while(run) {
                        TCPConn->ReadBuffer(VMes,sizeof(*mes));
                        mes = static_cast<Message*>(VMes);
                        mh.recvData(mes);
                        if(first_mess){
                             first_mess = false;
                             mh.getStartDateTime(*(this->Edit2));
                        }
                        if(mh.checkCRC()) {
                                gh.plot(mh, this->Series1);
                                Chart1->Update();
                        }
                }
            } catch(EIdConnClosedGracefully& e) {
                lboxResult->Items->Add("caught EIdConnClosedGracefully");
            }
        }__finally {
                if(TCPConn->Connected()){
                        TCPConn->Disconnect();
                        lboxResult->Items->Add("Disconnected");
                        this->StatusBar1->SimpleText = "";
                        TCPConn->DisconnectSocket();
                }
                free(VMes);
                ConnectButton->Enabled = true;
                this->StatusBar1->SimpleText = "  Stopped!";
        }
}
The stop button could be click on at any time
void __fastcall TForm1::stopButtonClick(TObject *Sender)
{
        run = false;
        this->StatusBar1->SimpleText = "  Stopped!";
}
0
mikrodidaktAuthor Commented:
I have increased the point value
0
2266180Commented:
I am just curious: if you are doing this all in borland C, why did you post on delphi?
0
mikrodidaktAuthor Commented:
Because the documentationon for indy is not that god for C++builder. But i think it is the best commponent for TCP.
And even if there is some problems for me as a C++programmer to understand everything in Delphi the basic is the same.
I have put some questions in C++ forum but there is not that many that is using Indy as it is in Delphi so i thought i ought to try the Delphi forum.
This question might have got a bit to big so i thank every one for there time and if no one have posted any new
comments by tommorow i will delete this.

Thanks every one for your time.

 
0
2266180Commented:
I looked over the client code, and
                while(run) {
seems like a dead end at least in delphi.

when you click on a button and have an semi-infinite cycle in it without an application.processmessages, it will run forever.
check such cycles, and try to avoid them. better use a trhead instead of that while thing in the vcl thread. it's too ugly and hard to control if you don't know vcl well enough
0
TheRealLokiSenior DeveloperCommented:
ah the plot thickens
well i don't know much about c++ builder but this should do the trick anyway

dynamically create the TCPConn in your button click, and free it at the end
this will reliably clean up the used socket port
I'll use a mix of delphi and c++ code, but you should be able to work it out
var
    TCPConn: TidTCPClient;
begin
  TCPConn := TidTCPClient.create(nil)
  TCPConn.port := 2000;
  TCPConn.host := 'localhost';
  try
      try{
            try{
                TCPConn->Connect();

.. other code here

            } catch(EIdConnClosedGracefully& e) {
                lboxResult->Items->Add("caught EIdConnClosedGracefully");
            }
        }__finally {
                if(TCPConn->Connected()){
                        TCPConn->Disconnect();
                        lboxResult->Items->Add("Disconnected");
                        this->StatusBar1->SimpleText = "";
                        TCPConn->DisconnectSocket();
                }
        }

  finally
    TCPConn.Free; // get rid of it
  end;
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mikrodidaktAuthor Commented:
That might work but will TAntiFreeze component work then?
I will give you the points TheRealLoki.
0
TheRealLokiSenior DeveloperCommented:
should do, the TidTCPClient components (etc) "self - registers" themselves with the TidAntiFreeze
but just to be safe, do TCPConn := TidTCPClient.create(Form1) instead of (nil)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.