arch
arch

Reputation: 471

How to ping a php page using c++?

I want to be able to signal to my website that my c++ application is currently running. What I have done so far is use libcurl to contact a PHP file on my website with some get parameters.
This is the C++ code:

curl_global_init(CURL_GLOBAL_ALL);
CURL * handle = curl_easy_init();
CURLcode result;
std::string url, contents;

std::cin >> url;

curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, &errorBuf[0]);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &contents);

while(true)
{
    time_t startOfLoop = time(0);
    //Ping page
    result = curl_easy_perform(handle);

    if(result == 0)
        std::cout << "[" << time(0) << "]: Pinged \"" << url << "\" ok!\r\n";
    else
    {
        std::cout << "[" << time(0) << "]: Pinged \"" << url << "\" **ERROR: " << errorBuf << " [Error Code: " << result << "]\r\n";
    }

    //Pause until 5 seconds has passed
    while(difftime(time(0), startOfLoop) < 5) {}
}
curl_easy_cleanup(handle);

The PHP file then writes to a MySQLi database to say the program has pinged in. This page is loaded once every 5 seconds in the application, and worked perferctly.

However, after a certain amount of time the website stops accepting requests. http://www.downforeveryoneorjustme.com/ says the site is still online, but I get Oops! Google Chrome could not connect, and the curl application just spits out **ERROR: Failed connect to [site-url]:80; No error [Error Code: 7] for period of time until the website decides to start allowing requests again.

Is this a problem with the webhosts I am using? (000webhost), Do I just need to upgrade to a better webhost with more bandwidth?

Or am I going about this the wrong way? Is there a better way to contact my site from a c++ application?

Any help would be greatly appreciated.
Thanks!

Upvotes: 0

Views: 1018

Answers (1)

Chris Olsen
Chris Olsen

Reputation: 3511

What you describe sounds to me like all available TCP sockets in the server's pool are getting used up (put into ESTABLISHED or TIME_WAIT state for example). Once a socket has been closed, it goes into TIME_WAIT state for a period of time (usually 4 minutes). After this time, it's available to be used again. So if your server is configured with a very small number of sockets (<250), and curl is using a new socket each time, then this could be the problem.

If you have the access, you could run netstat on the server to check the current state of the sockets.

However, by default curl should be using persistent keep-alive connections. According to the documentation curl_easy_perform should be attempting to reuse the connection, so in theory you should not be seeing this problem (unless the server is not configured to use keep-alives I suppose).

Also, your code has a few errors so I wonder if there could be some undefined behavior happening. I'd recommend fixing these errors and see if the problem still occurs.

  1. Use url.c_str() instead of url in curl_easy_setopt(handle, CURLOPT_URL, url);

  2. Pass a pointer to a buffer, not a string in curl_easy_setopt(handle, CURLOPT_WRITEDATA, &contents);

  3. According to the documentation for curl_easy_perform, curl_easy_setopt should be called before every call to curl_easy_perform, so try moving the setopts inside the loop.

I copied your code into a test app and modified it to test on my system. It worked fine. Here's my complete code:

#include <iostream>
#include <string>
#include <thread>
#include <curl/curl.h>

using namespace std;

char errorBuf[CURL_ERROR_SIZE];
char contents[CURL_MAX_WRITE_SIZE];
std::string url;
size_t received_len = 0;

size_t write_func( char *ptr, size_t size, size_t nmemb, void *userdata)
{
    size_t len = size*nmemb;
    received_len += len;
    return len;
}

int main()
{
    curl_global_init(CURL_GLOBAL_ALL);
    CURL * handle = curl_easy_init();
    CURLcode result;

    cout << "Enter URL:";
    cin >> url;

    while(true)
    {
        received_len = 0;

        // Set options before each call to curl_easy_perform()
        curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
        curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errorBuf);
        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func);
        curl_easy_setopt(handle, CURLOPT_WRITEDATA, contents);

        // Invoke the URL
        if((result = curl_easy_perform(handle)) == 0)
            cout << "[" << time(0) << "]: \"" << url << "\" Received " << received_len << " bytes ok!\n";
        else
            std::cout << "[" << time(0) << "]: \"" << url << "\" **ERROR: " << errorBuf << " [Error Code: " << result << "]\n";

        // Pause until 5 seconds has passed
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }

    // NOTE: This will never be called
    curl_easy_cleanup(handle);

    return 0;
}

Upvotes: 2

Related Questions