Page 1 of 1

Check if an indy Http server is active by indy client issue!

PostPosted: Tue Mar 12, 2019 7:53 am
by Ahmed Sayed
Hi I am creating an app to monitor some of my http servers so in case they are down I get notified by email.

I used this code to check for the connection if it is active or not:

Code: Select all
bool SocketIsOpen( UnicodeString Host, int Port, String &Msg, int ATimeout)
{
unique_ptr<TIdTCPClient> Socket(new TIdTCPClient(nullptr));
Msg = "";
bool res = false;
try
   {
   Socket->ConnectTimeout = ATimeout;
   try
      {
      Socket->Connect( Host, Port);
      res = Socket->Connected();
      }
   catch (const Exception &E)
      {
      Msg = E.Message;
      res = false;
      }
   }
__finally
   {
   Socket->Disconnect();
   }
return res;
}
//---------------------------------------------------------------------------


I used this function periodically every 500 MS and the timeout is 1 MS but sometimes I get Connection timeout. The monitoring app and the servers are on the same machine so i don't think there should be any timeouts. The server itself is active all the time.

Actually what I am trying to do is monitor the following for each server:
Memory - CPU usage - No. Connections - Threads - detect if server is responding or not - TIdHttpServer is active or not

The reason why I use 1 Ms as timeout is that I don't want all the previous checks take a lot of time. There is an interval of 500 Ms between a check is made on all server process and the next check.

For example, if I have 4 servers running above data is collected for each server then wait for 500 Ms and then collect data for all servers again.

So is their a way to do so with speed with no timeouts.
Thanks in advance

Re: Check if an indy Http server is active by indy client is

PostPosted: Wed Mar 13, 2019 12:01 am
by mark_c
always if I understand your problem: and setting a timeout of 100 ms instead of 1 ms what happens?

Re: Check if an indy Http server is active by indy client is

PostPosted: Fri Mar 15, 2019 7:39 am
by Ahmed Sayed
If i changed the timeout to 100 MS sure the process will get slower and it still timeout from time to time like giving me 7 timeouts in 1 minute during monitoring 4 servers.

Re: Check if an indy Http server is active by indy client is

PostPosted: Wed Apr 17, 2019 1:19 pm
by rlebeau
Ahmed Sayed wrote:If i changed the timeout to 100 MS sure the process will get slower and it still timeout from time to time like giving me 7 timeouts in 1 minute during monitoring 4 servers.


That is to be expected, as even 100ms may be too short at times. There is overhead in establishing a new TCP connection (3-way handshake), as well as overhead in how Indy implements its ConnectTimeout (using a worker thread). So, you really should specify a timeout in seconds rather than in milliseconds.

For that matter, since you are doing real-time monitoring, why drop a connection and reconnect at 500ms intervals at all? Why not just establish a connection and leave it open? You will be notified if the connection is closed, such as when the server is shut down or killed.

Otherwise, I would suggest using the socket API directly to cut down on overhead, eg:

Code: Select all
#include <winsock2.h>
#include <ws2tcpip.h>
#include <vector>
#include <memory>

struct SocketDeleter
{
    typedef SOCKET pointer;

    void operator()(SOCKET s) const
    {
        if (s != INVALID_SOCKET)
        {
            int err = WSAGetLastError();
            closesocket(s);
            WSASetLastError(err);
        }
    }
};

bool SocketIsOpen(const UnicodeString &Host, short Port, String &Msg, int ATimeout)
{
    Msg = _D("");

    try
    {
        ADDRINFOW hints = {}, *addrs;

        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;

        if (GetAddrInfoW(Host.c_str(), UnicodeString(Port).c_str(), &hints, &addrs) != 0)
            RaiseLastOSError(WSAGetLastError());

        std::vector<std::unique_ptr<SOCKET, SocketDeleter>> sockets;

        {
        std::unique_ptr<ADDRINFOW, decltype(&::FreeAddrInfoW)> addrs_deleter(addrs, &FreeAddrInfoW);

        for (ADDRINFOW *addr = addrs; addr != NULL; addr = addr->ai_next)
        {
            SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
            if (sock != INVALID_SOCKET)
            {
                std::unique_ptr<SOCKET, SocketDeleter> sock_deleter(sock);

                u_long mode = 1;
                if (ioctlsocket(sock, FIONBIO, &mode) == 0)
                {
                    connect(sock, addr->ai_addr, addr->ai_addrlen);
                    if (WSAGetLastError() == WSAEWOULDBLOCK)
                        sockets.push_back(std::move(sock_deleter));
                }
            }
        }

        if (sockets.empty())
            RaiseLastOSError(WSAGetLastError());
        }

        fd_set fds;
        FD_ZERO(&fds);
        for(auto &sock : sockets) {
            FD_SET(sock.get(), &fds);
        }

        timeval tv = {};
        tv.tv_sec = ATimeout / 1000;
        tv.tv_usec = (ATimeout & 1000) * 1000;

        int err = select(0, NULL, &fds, NULL, &tv);
        if (err < 0)
            RaiseLastOSError(WSAGetLastError());

        return (err > 0);
    }
    catch (const Exception &E)
    {
        Msg = E.Message;
        return false;
    }
}
//---------------------------------------------------------------------------

Re: Check if an indy Http server is active by indy client is

PostPosted: Wed Apr 17, 2019 1:56 pm
by Ahmed Sayed
For that matter, since you are doing real-time monitoring, why drop a connection and reconnect at 500ms intervals at all? Why not just establish a connection and leave it open? You will be notified if the connection is closed, such as when the server is shut down or killed.

You mean using a TIdTCPClient or so and leave the connection open but the server i am monitoring is REST server so there is no KeepAlive enabled for this one. Is it possible to make a client force a server to keep the connection open even if the server KeepAlive property is false?

Re: Check if an indy Http server is active by indy client is

PostPosted: Wed Apr 17, 2019 4:53 pm
by rlebeau
Ahmed Sayed wrote:You mean using a TIdTCPClient or so and leave the connection open


Yes. Then you can monitor the state of that connection, rather than wasting time and resources tearing down connections and recreating them on a regular basis.

Ahmed Sayed wrote:but the server i am monitoring is REST server so there is no KeepAlive enabled for this one.


Then have your server open another port that your monitoring app can connect to. This also gives you the benefit of having the server app monitor its own vitals and report them to monitoring clients as needed, instead of having the clients try to figure out what is going on.

Ahmed Sayed wrote:Is it possible to make a client force a server to keep the connection open even if the server KeepAlive property is false?


Not in the HTTP protocol, no. But that doesn't mean you have to limit your server to just HTTP. Or, you could open multiple HTTP ports, where REST without KeepAlive is on one port, and monitoring with KeepAlive is on another port.

Re: Check if an indy Http server is active by indy client is

PostPosted: Wed Apr 17, 2019 5:39 pm
by Ahmed Sayed
Thanks, But how can check the status of the client connection? and how can create another port for TIdHTTPServer with keepalive enabled for that server? or do i have to place another server component for monitoring. because the idea is to monitor that specific server.

Re: Check if an indy Http server is active by indy client is

PostPosted: Wed Apr 17, 2019 10:47 pm
by rlebeau
Ahmed Sayed wrote:how can check the status of the client connection?


Perform I/O on it periodically and check for errors.

Ahmed Sayed wrote:how can create another port for TIdHTTPServer with keepalive enabled for that server?


Use separate TIdHTTPServer instances. Or, use a single TIdHTTPServer instance with multiple Bindings assigned and KeepAlive enabled, then in the OnCommand... event(s) you can set AResponseInfo.CloseConnection based on which Binding port received the request.