0

I am trying to run a CPP client application to connect to a server when Raspberry Pi is booted and connected to the Internet. I validated this CPP executable (Asio_Client_Main) works fine when manually run in the terminal. (pi@raspberrypi:~/Desktop $ ./Asio_Client_Main - Once connected, it sends a message to a server.)

First time to use Systemd, and this is what I did.

  1. made client_test_a.service and copied it to /etc/systemd/system/
[Unit]
Description=Client Test A
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
WorkingDirectory=/home/pi/Desktop
ExecStart=/home/pi/Desktop/Asio_Client_Main

StandardOutput=console

[Install]
WantedBy=multi-user.target
  1. sudo systemctl start client_test_a.service

  2. sudo systemctl status client_test_a.service

● client_test_a.service - Client Test A
   Loaded: loaded (/etc/systemd/system/client_test_a.service; enabled; vendor pr
   Active: inactive (dead) since Sun 2021-02-07 18:00:02 EST; 10min ago
  Process: 1586 ExecStart=/home/pi/Desktop/Asio_Client_Main (code=exited, status
 Main PID: 1586 (code=exited, status=0/SUCCESS)

Feb 07 18:00:02 raspberrypi systemd[1]: Started Client Test A.
Feb 07 18:00:02 raspberrypi systemd[1]: client_test_a.service: Succeeded.
  1. sudo systemctl enable client_test_a.service

It's loaded but inactive. I think it's just exited, but how can I keep it connected? I also don't think it's connected to the server because I don't see any client connection on the server-side. Any advice would be appreciated. Thanks!

I tried Type=oneshot. Using RPi 4 B with wifi connection.

Main Cpp Code

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include "Asio_Client.h"

int main(int argc, char* argv[])
{
    std::vector<std::vector<int>> lunarPixel;
    
    std::ifstream file("LunarPixel.txt");
    std::string str;

    while (std::getline(file, str))
    {
        // Process str
        std::vector<int> result;
        std::istringstream iss(str);

        for (std::string str; iss >> str;)
        {
            result.push_back(std::stoi(str));
        }

        lunarPixel.push_back(result);
    }

    auto& lunar_time = lunar_timer::Init();
    lunar_time.set_lunar_pixel(lunarPixel);

    
    //--------------------------------------------------------------------------------------------------------------
    
    
    try
    {
        std::vector<std::vector<int>> lunarPixel;

        std::ifstream file("LunarPixel.txt");
        std::string str;

        while (std::getline(file, str))
        {
            // Process str
            std::vector<int> result;
            std::istringstream iss(str);

            for (std::string str; iss >> str;)
            {
                result.push_back(std::stoi(str));
            }

            lunarPixel.push_back(result);
        }

        auto& lunar_time = lunar_timer::Init();
        lunar_time.set_lunar_pixel(lunarPixel);

        boost::asio::io_context io_context;
        tcp::resolver resolver(io_context);

        const std::string ipAddress = "192.***.*.*"; //ip
        const std::string portNum = "2120";

        auto endpoints = resolver.resolve(ipAddress, portNum);
        chat_client c(io_context, endpoints, lunar_time);

        std::thread t([&io_context]() { io_context.run(); });

        char line[chat_message::max_body_length + 1];
        
        std::cout << "Before_ while (std::cin.getline(line, chat_message::max_body_length + 1))" << std::endl; 

        while (std::cin.getline(line, chat_message::max_body_length + 1))
        {
            chat_message msg;
            msg.body_length(std::strlen(line));
            std::memcpy(msg.body(), line, msg.body_length());
            msg.encode_header();
            c.write(msg);
        }

        std::cout << "Exited" << std::endl;  

        c.close();
        t.join();
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

UPDATE 2/9/2021:

Prints before and after While Loop Please see the Main.cpp Above to see the complete code

std::cout << "Before_ while (std::cin.getline(line, chat_message::max_body_length + 1))" << std::endl; 

while (std::cin.getline(line, chat_message::max_body_length + 1))
{
    chat_message msg;
    msg.body_length(std::strlen(line));
    std::memcpy(msg.body(), line, msg.body_length());
    msg.encode_header();
    c.write(msg);
}

std::cout << "Exited" << std::endl; 

I also used a bash script instead of executing the program directly.

mystartup.sh

#!/bin/bash
# Store first parameter in a variable, which should be the log file location.
LOG_FILE="$1"
# Set a default log file location if the parameter was empty, i.e. not specified.
if [ -z "$LOG_FILE" ]
then
  LOG_FILE="/var/log/testlog.txt"
fi

cd /home/pi/Desktop
./Asio_Client_Main

Then

sudo systemctl start client_test_a.service sudo systemctl status client_test_a.service

● client_test_a.service - Client Test A
   Loaded: loaded (/etc/systemd/system/client_test_a.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Tue 2021-02-09 23:09:58 EST; 3s ago
  Process: 2004 ExecStart=/bin/bash /usr/local/bin/mystartup.sh (code=exited, status=0/SUCCESS)
 Main PID: 2004 (code=exited, status=0/SUCCESS)

Feb 09 23:09:58 raspberrypi bash[2004]: Before_ while (std::cin.getline(line, chat_message::max_body_length + 1))
Feb 09 23:09:58 raspberrypi bash[2004]: Exited
Feb 09 23:09:58 raspberrypi systemd[1]: client_test_a.service: Succeeded.
Feb 09 23:09:58 raspberrypi systemd[1]: Started Client Test A.

So when I ran the program, it does not exit the loop. But when using systemd, it just exits the loop without taking user inputs. How can I keep running in the foreground taking user inputs?

13
  • Does the program, executed from the command line, run short and finished successfully, or does it stay running until you kill it for example with Ctrl-C? – Ingo Feb 8 at 1:12
  • @Ingo It stays connected until I kill it. – mqmarathon Feb 8 at 1:47
  • you ask how can I keep it connected? ... but your comment states It stays connected ... so is the process running or not? Also, can you describe what Asio_Client_Main does on startup, as in, does it fork off a new process that runs as a daemon for example? Also, is it supposed to run as root? – Jaromanda X Feb 8 at 2:12
  • @JaromandaX It stays connected when I run it in a command line (It's compiled and executed properly that way.) I want it to automatically run on startup. I don't think it's ever properly executed making a connection to the server with Systemd. – mqmarathon Feb 8 at 2:23
  • oh, right, misunderstood - does it run in the background or foreground when you start it like ./Asio_Client_Main – Jaromanda X Feb 8 at 2:24
3

From the status as shown everything seems OK so far. It shows that the program has run and finished successfully with code=exited, status=0/SUCCESS. No problems seen by systemd. I did not understand the program at a glance, and didn't take the effort to analyze it. Does this program has some exit points in case of an error? If so, then exit there with exit code 1. this will cause systemd to terminate the service with an error, and you will know it does not run successfully. A printf with an error message is also useful there. You will find these messages in the systemd journal, shown with journalctl.

If it runs in the foreground on the command line, it is OK. Don't change it. Systemd will manage to run it as service in the background with full control about it. So the service must run until you stop it with:

rpi ~$ sudo systemctl stop client_test_a.service

I assume you are running it on the command line as user pi. So I suggest to try it also with the Unit. To summarize it I would use this Unit:

[Unit]
Description=Client Test A
Wants=network-online.target
After=network-online.target

[Service]
User=pi
Group=pi
WorkingDirectory=/home/pi/Desktop
ExecStart=/home/pi/Desktop/Asio_Client_Main

[Install]
WantedBy=multi-user.target

It is important that the program runs until you stop it with systemctl, or until it terminates with an error/exit code greater than 0.

3
  • Hi Ingo, thanks a lot. It really helped to find the problem. It looks like the problem is the While loop that's taking a user input. (Please see the updated section in the post.) When running the program, it stays in the loop. But when running through systemd, it just exits. How can I keep it running in the foreground and taking user inputs? – mqmarathon Feb 10 at 4:38
  • I also tried Type=simple instead of oneshot. Still just exting – mqmarathon Feb 10 at 4:54
  • @mqmarathon Systemd is made to start programs as silent services in the background. It isn't made for user interaction. This will break its intended working and service management. Forget it. – Ingo Feb 11 at 20:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.