Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

How to disconnect to a indy server?

Posted on 2006-07-10
23
977 Views
Last Modified: 2011-10-03
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
0
Comment
Question by:mikrodidakt
  • 11
  • 5
  • 4
  • +1
23 Comments
 
LVL 28

Expert Comment

by:2266180
ID: 17071080
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
 
LVL 10

Expert Comment

by:atul_parmar
ID: 17071219
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
 

Author Comment

by:mikrodidakt
ID: 17071248
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
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 

Author Comment

by:mikrodidakt
ID: 17071258
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
 

Author Comment

by:mikrodidakt
ID: 17071268
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
 
LVL 10

Expert Comment

by:atul_parmar
ID: 17071325
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
 

Author Comment

by:mikrodidakt
ID: 17071415
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
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17071449
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
 
LVL 10

Expert Comment

by:atul_parmar
ID: 17071451
0
 

Author Comment

by:mikrodidakt
ID: 17071520
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
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17077616
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
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17077720
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
 

Author Comment

by:mikrodidakt
ID: 17079512
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
 
LVL 28

Expert Comment

by:2266180
ID: 17079565
why don't you post your code :) I'm sure we can help you faster that way ;)
0
 

Author Comment

by:mikrodidakt
ID: 17079770
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
 

Author Comment

by:mikrodidakt
ID: 17079792
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
 

Author Comment

by:mikrodidakt
ID: 17079796
I have increased the point value
0
 
LVL 28

Expert Comment

by:2266180
ID: 17079916
I am just curious: if you are doing this all in borland C, why did you post on delphi?
0
 

Author Comment

by:mikrodidakt
ID: 17081779
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
 
LVL 28

Expert Comment

by:2266180
ID: 17081993
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
 
LVL 17

Accepted Solution

by:
TheRealLoki earned 500 total points
ID: 17084970
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
 

Author Comment

by:mikrodidakt
ID: 17088413
That might work but will TAntiFreeze component work then?
I will give you the points TheRealLoki.
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17088657
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

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question