I am trying to run an 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.
[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
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 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.
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 it running in the foreground taking user inputs?
Systemd is not designed for programs with console interaction. It's designed for background services or tasks to run on system events.
As such unless you use redirection in your bash script std::cin will not be connected to anything (let alone a terminal - which terminal should it use anyways?).
If you're going to run a chat server as a background service, make the part without user interaction the service executable. For example, the service need only accept input via network connections and optionally write additional output to a file (such as logging) .
If the program should read some thing like configuration from standard input, use input redirection to read it from a file instead.