It must working independently. By working independently I means that if one program shuts down, the other one will continue to work.
I tried to use library named 'atomic' to catch exeptions and reconnect to the program2 but it's doesn't work.
Program 1.
#include <iostream>
#include <algorithm>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <future>
#include <atomic>
#include "library.h"
std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> connected{false};
std::mutex atom_mtx;
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8080
int sockfd;
struct Message
{
std::promise<void> promise;
std::string message;
};
std::queue<Message> buffer;
// Server connection function (program 2)
void connect_to_server()
{
connected.store(false);
while (true)
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
std::cerr << "Error creating socket\n";
continue;
}
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVER_PORT);
int error_inet_pton = inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr);
if (error_inet_pton == 0)
{
std::cerr << "Bad IP address\n";
close(sockfd);
continue;
}
else if (error_inet_pton < 0)
{
std::cerr << "Error converting IP address\n";
close(sockfd);
continue;
}
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0)
{
std::cout << "Connected to server program 2\n";
connected.store(true);
break;
}
else
{
std::cerr << "Error connecting to program2, trying again...\n";
sleep(2);
close(sockfd);
continue;
}
}
}
void thread1()
{
std::string str;
while (true)
{
{
std::lock_guard<std::mutex> lock(atom_mtx);
if (!connected.load())
{
std::cerr << "No connection to the server" << std::endl;
connect_to_server();
}
}
std::cout << std::endl<< "Enter line: ";
std::getline(std::cin, str);
std::promise<void> promise;
auto future = promise.get_future();
{
std::unique_lock<std::mutex> lock(mtx);
if (str == "exit")
break;
if (str.size() > 64 || !std::all_of(str.begin(), str.end(), ::isdigit) || str.empty())
{
std::cerr << "The string must consist only of numbers and not exceed 64 characters.\n";
continue;
}
sort_and_replace(str);
buffer.push({std::move(promise), str});
}
cv.notify_one();
future.wait();
}
}
void thread2()
{
while (true)
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return !buffer.empty(); });
Message message = std::move(buffer.front());
buffer.pop();
std::cout << "Processed line: " << message.message << std::endl;
message.promise.set_value();
size_t sum = sum_of_digits(message.message);
std::string sum_str = std::to_string(sum);
if (send(sockfd, sum_str.c_str(), sum_str.size(), 0) < 0)
{
std::cerr << "Error sending data.\n";
close(sockfd);
connected.store(false);
connect_to_server();
}
}
}
int main()
{
connect_to_server();
std::thread t1(thread1);
std::thread t2(thread2);
t1.join();
t2.join();
close(sockfd);
return 0;
}
Program 2.
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "library.h"
#define PORT 8080
#define BACKLOG 10
void start_server() {
int server_fd, client_socket;
struct sockaddr_in address;
socklen_t addrlen = sizeof(address);
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == 0) {
std::cerr << "Error creating socket\n";
return;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
std::cerr << "Binding error\n";
return;
}
if (listen(server_fd, BACKLOG) < 0) {
std::cerr << "Error while listening\n";
return;
}
std::cout << "Waiting for connection from program1...\n";
while (true) {
client_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen);
if (client_socket < 0) {
std::cerr << "Error accepting connection\n";
continue;
}
std::cout << "Connection established with program1\n";
char buffer[1024] = {0};
while (true) {
int valread = recv(client_socket, buffer, sizeof(buffer), 0);
if (valread == 0) {
std::cerr << "Connection lost, waiting for new connection...\n";
close(client_socket);
break;
}else if(valread < 0)
{
std::cerr<< "Error reading data\n";
close(client_socket);
break;
}
std::string received_data(buffer, valread);
bool result = lenght_analize(received_data);
if (result) {
std::cout << "true\n";
} else {
std::cout << "error\n";
}
}
}
close(server_fd);
}
int main() {
start_server();
return 0;
}
When programs are launched in different orders (either first the first program then the second, or vice versa), they really do work independently. I can send data by specifying it in program 1 to the server program 2. But as soon as I turn off the server (control + c), in program 1 I continue to be asked to enter lines, and after two lines have been entered, program 1 turns itself off. But I need the first program not to turn off.
Sample output: Program 1:
Error connecting to program2, retrying...
Error connecting to program2, retrying...
Error connecting to program2, retrying...
Connected to server program2
Enter line: 1234
Processed line: KB3KB1
Enter line: 1234
Processed line: KB3KB1
(after this message, I turned off program 2, but anyway it asked to enter line)
Enter line: 123
Processed line: 3KB1
Enter line: 123
Processed line: 3KB1
(program1 turned off after this)
Program 2:
Waiting for connection from program1...
Connection established with program1
error
error
^C
I neet something like this: Program 1:
Error connecting to program2, retrying...
Error connecting to program2, retrying...
Error connecting to program2, retrying...
Connected to server program2
Enter line: 1234
Processed line: KB3KB1
Enter line: 1234
Processed line: KB3KB1
(after this message, I turned off program 2)
Lost connection, trying to reconnect...
(Now I have launched the 2nd program)
Connection established
Enter line: 1234
Processed line: KB3KB
...
Program 2:
Waiting for connection from program1...
Connection established with program1
error
error
^C
./program2(started program 2 again)
Waiting for connection from program1...
Connection established with program1
error
How can I get this?
The problem is that the SIGPIPE signal terminates the program and the connection to the server is not implemented securely. It would be safer to entrust the reconnection work to one thread.
To ignore SIGPIPE:
#include <signal.h>
...
...
...
int main():
signal(SIGPIPE, SIG_IGN);
...
And from thread1 need to remove reconnection part:
{
std::lock_guard<std::mutex> lock(atom_mtx);
if (!connected.load())
{
std::cerr << "No connection to the server" << std::endl;
connect_to_server();
}
}