C++ - msgsnd & msgrcv communication between 2 different programs - c++

I have two programs and I want them to communicate together by msgrcv() && msgsnd(). I so have a master program which init the message queue and start the 2 others programs:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int qid = msgget(ftok(".",'u'), 0);
char* params[3];
params[1] = (char *)malloc(sizeof(char) * 9);
sprintf(params[1], "%d", qid);
params[2] = NULL;
printf("qid = %d and qid(str) = %s", qid, params[1]);
// return (0);
//spawning two child processes
pid_t cpid = fork();
if (cpid == 0) {
params[0] = (char*)"./sender";
execv(params[0], params);
exit(0);
}
cpid = fork();
if (cpid == 0) {
params[0] = (char*)"./receiver";
execv(params[0], params);
exit(0);
}
while (wait(NULL) != -1); // waiting for both children to terminate
msgctl(qid, IPC_RMID, NULL);
std::cout << "parent proc: " << getpid()
<< " now exits" << std::endl;
exit(0);
}
I also prepare the parameters and start the both following programs:
sender
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int ac, char **av) {
if (ac != 2)
return (-1);
// create my msgQ with key value from ftok()
// int qid = msgget(IPC_PRIVATE, IPC_EXCL|IPC_CREAT|0600);
int qid = atoi(av[1]);
// declare my message buffer
struct buf {
long mtype; // required
char greeting[50]; // mesg content
};
buf msg;
int size = sizeof(msg)-sizeof(long);
std::cout << "Welcome in the prog assignment 2! Type [exit] to stop the program." << std::endl;
bool exit = false;
while (!exit)
{
std::cout << getpid() << ": ";
std::cin.getline(msg.greeting, 50, '\n');
std::cout << msg.greeting << std::endl;
msg.mtype = 114; // only reading mesg with type mtype = 114
if (strcmp(msg.greeting, "exit") == 0)
exit = true;
msgsnd(qid, (struct msgbuf *)&msg, size, 0);
}
}
receiver
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
int main(int ac, char **av) {
int i = 0;
while (i < ac)
printf("AV: %s\n", av[i++]);
if (ac != 2)
return (-1);
// int qid = msgget(IPC_PRIVATE, IPC_EXCL|IPC_CREAT|0600);
int qid = atoi(av[1]);
// declare my message buffer
struct buf {
long mtype;
char greeting[50];
};
buf msg;
int size = sizeof(msg)-sizeof(long);
bool exit = false;
while (!exit)
{
msgrcv(qid, (struct msgbuf *)&msg, size, 114, 0);
if (strcmp(msg.greeting, "exit") == 0)
exit = true;
std::cout << getpid() << msg.greeting << std::endl;
}
std::cout << "get out" << std::endl;
}
It doesn't work and I'm not sure to understand why because, I'm creating the message queue, passing it as parameter, then I put it back as int and then use it. However, it just gives me an infinite loop of weird display, why?
ANy help is welcome.. Thank !

Related

How to create or manage Libuv TCP server in a c++ fuction?

I am trying to create a TCP server in a function int create_server(int port_number, char ip_addr_string[IPV4_ADDR_SIZE]) which is called in main.
When I run the c++ code given below: Assertion failed: (w->fd >= 0), function uv__io_poll, file kqueue.c, line 149.
#include <iostream>
#include <vector>
#include <algorithm>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <future>
#include <sys/types.h>
#include <uv.h>
#define IPV4_ADDR_SIZE 15
uv_loop_t* loop;
struct sockaddr_in addr;
std::map <int, uv_tcp_t * > pool;
int create_tunnel(int port_number, char ip_addr_string[IPV4_ADDR_SIZE]){
uv_tcp_t global_server;
uv_tcp_init(loop, &global_server);
uv_ip4_addr("0.0.0.0", port_number, &addr);
uv_tcp_bind(&global_server, (const struct sockaddr *)&addr, 0);
int r = uv_listen((uv_stream_t *)&global_server, 128, NULL);
if(r){
fprintf(stderr, "Listen error: %s \n", uv_strerror(r));
}
else{
fprintf(stdout, "Listening on: %d \n", port_number);
}
pool[rand()] = &global_server;
return r;
}
int main(int argc, const char *argv[]){
int status = 1;
loop = uv_default_loop();
uv_loop_init(loop);
loop->data = &pool;
status = create_tunnel(7011, (char*)"0.0.0.0");
std::cout<< "status: " << status << std::endl;
uv_run(loop, UV_RUN_DEFAULT);
return 0;
I think this error is because the servers created are not tracked by the event_loop when the create_server function ends, but I am not sure.
Any help, please?

IPC using multiple pipes and forked processes to run Python programs

I am stuck with a problem for my assignment. I am trying to execute 3 concurrent processes (in C++) out of which 2 of them are Python programs and one of them is C++ program.
My C++ program (sample.cpp):
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <signal.h>
using namespace std;
int main()
{
while (true)
{
cout << "lol" << endl;
sleep(2);
}
return 0;
}
My Python program 1 (sample.py):
import sys
while True:
line = sys.stdin.readline().strip()
print "Python says: " + str(line)
My Python program 2 (sample2.py):
import sys
while True:
line = sys.stdin.readline().strip()
print "Python 2 says: " + str(line)
Here is my driver C++ program which forks processes:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <signal.h>
using namespace std;
int main()
{
vector<pid_t> kids;
int fd[2];
if (pipe(fd) < 0)
{
cout << "Error";
return 1;
}
int fd2[2];
if (pipe(fd2) < 0)
{
cout << "Error";
return 1;
}
pid_t pid;
pid = fork();
if (pid == 0)
{
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
while (true)
{
execvp("./sample", NULL);
}
}
else
{
kids.push_back(pid);
pid = fork();
if (pid == 0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
dup2(fd2[1], STDOUT_FILENO);
close(fd2[1]);
close(fd2[0]);
char * python = "/usr/bin/python";
char * pythonProgram = "./sample.py";
char * pythonArgs[] = {python, pythonProgram, NULL, NULL};
execvp(python, pythonArgs);
}
else
{
kids.push_back(pid);
pid = fork();
if (pid == 0)
{
dup2(fd2[0], STDIN_FILENO);
close(fd2[0]);
close(fd2[1]);
char * python = "/usr/bin/python";
char * pythonProgram = "./sample2.py";
char * pythonArgs[] = {python, pythonProgram, NULL, NULL};
execvp(python, pythonArgs);
}
else
{
kids.push_back(pid);
}
}
}
close(fd[0]);
close(fd[1]);
close(fd2[0]);
close(fd2[1]);
for (pid_t k : kids)
{
int status;
//kill (k, SIGTERM);
waitpid(k, &status, 0);
}
}
When I run this program, I am expected to see "Python 2 says: Python says: lol". However, I see nothing (complete blank)... it just hangs. What am I doing wrong? I tried looking up a lot of things but no luck.
The while loop around the start of ./sample is pointless unless you expect execvp to fail. A successful call to exec* will never return. The actual call to execvp is wrong too:
execvp("./sample", NULL);
the second argument should be a char *const[].
You should add error handling for execvp:s (like a line with std::exit(1)). Otherwise if execvp fails, you'll have child processes running in the main flow of the program.
The python programs needs to be run unbuffered or else it will take a long time for the messages to appear. You should also check if the readline succeeded.
sample.py
import sys
while True:
line = sys.stdin.readline().strip()
if not line: break
print "Python says: " + str(line)
sample2.py
import sys
while True:
line = sys.stdin.readline().strip()
if not line: break
print "Python 2 says: " + str(line)
driver.cpp
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main()
{
vector<pid_t> kids;
int fd[2];
if (pipe(fd)==-1)
{
clog << "Error\n";
return 1;
}
int fd2[2];
if (pipe(fd2)==-1)
{
clog << "Error\n";
return 1;
}
pid_t pid;
pid = fork();
if (pid == 0)
{
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
char* const args[] = { NULL };
execvp("./sample", args);
std::clog << "sample failed\n";
std::exit(1);
}
else
{
kids.push_back(pid);
pid = fork();
if (pid == 0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
dup2(fd2[1], STDOUT_FILENO);
close(fd2[1]);
close(fd2[0]);
char const* python = "/usr/bin/python";
char const* pythonProgram = "./sample.py";
char const* pythonArgs[] = {python, "-u", pythonProgram, NULL};
execvp(python, const_cast<char* const*>(pythonArgs));
std::clog << "sample.py failed\n";
std::exit(1);
}
else
{
kids.push_back(pid);
pid = fork();
if (pid == 0)
{
dup2(fd2[0], STDIN_FILENO);
close(fd2[0]);
close(fd2[1]);
char const* python = "/usr/bin/python";
char const* pythonProgram = "./sample2.py";
char const* pythonArgs[] = {python, "-u", pythonProgram, NULL};
execvp(python, const_cast<char* const*>(pythonArgs));
std::clog << "sample2.py failed\n";
std::exit(1);
}
else
{
kids.push_back(pid);
}
}
}
close(fd[0]);
close(fd[1]);
close(fd2[0]);
close(fd2[1]);
for (pid_t k : kids)
{
int status;
//kill (k, SIGTERM);
waitpid(k, &status, 0);
}
}

Restart a program of child process in C++ linux

I have learned recently about processes and threads, and I am building a project where I need to run a program inside a child process.
The problem is that after the program in the child process exits I don't know how to restart and run the program again.
Here's a test which demonstrates what I am trying to do.
main.cpp file:
#include <iostream>
#include <unistd.h>
#include <sys/ptrace.h>
#include "handler.h"
int main(int argc, char** argv)
{
if (argc < 2)
{
std::cerr << "usage: program name" << std::endl;
return 1;
}
pid_t pid = fork();
if (pid == 0)
{
if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) < 0)
std::cerr << "ptrace error" << std::endl;
else
execl(argv[1], argv[1], nullptr);
}
else if (pid >= 1)
{
Handler handler(std::string(argv[1]), pid);
handler.run();
}
}
handler.h file:
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <sys/ptrace.h>
#include <sys/wait.h>
class Handler
{
private:
pid_t m_pid;
std::string m_name;
public:
Handler(const std::string& name, pid_t pid) : m_name(name), m_pid(pid)
{
}
void run()
{
std::string line;
while (true)
{
std::cout << "(command) ";
std::getline(std::cin, line);
if (line == "run")
{
int options = 0, status = 0;
ptrace(PTRACE_CONT, m_pid, nullptr, nullptr);
int pid = waitpid(m_pid, &status, options);
// trying to restart again the program
if (pid < 0)
{
m_pid = fork();
execl(m_name.c_str(), m_name.c_str(), nullptr);
}
}
}
}
};

c++ pipe buffering disable

How to disable buffering in pipe. I'm creating a simple recorder/player for I/O. To do this I need record output witch time delays.
To record delays, I need something like this
example tekst
"wait 1s"
example tekst
"wait 1s"
example tekst
...
but if I use
pipe2(in, O_DIRECT );
i see something like this
"wait 100s"
"100 times" example tekst
"wait 100s"
"100 times" example tekst
...
man7 tells:
O_DIRECT (since Linux 3.4)
Create a pipe that performs I/O in "packet" mode. Each
write(2) to the pipe is dealt with as a separate packet, and
read(2)s from the pipe will read one packet at a time.
I tried to disable buffering, by:
fcntl(in[1], F_SETPIPE_SZ, 1);
but it's still not working.
read.cpp
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <assert.h>
bool keep = true;
void intHandler(int dummy) {
keep = 0;
}
int main(void) {
signal(SIGINT, intHandler);
int in[2];
int out[2];
int pid;
int fo;
char buf[1024];
pipe2(in, O_DIRECT );
pipe2(out, O_DIRECT );
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
close(in[0]);
close(out[1]);
close(0);
close(1);
dup2(in[1], 1);
dup2(out[0], 0);
close(in[1]);
close(out[0]);
sleep(1);
char *newargv[] = {"/root/Pulpit/a1", NULL, NULL, NULL};
char *newenviron[] = {NULL};
int ret = execve("/root/Pulpit/a1", newargv, newenviron);
printf("%d", ret);
return 0;
} else {
close(out[0]);
close(in[1]);
int n = 0;
while (keep) {
int wyn = read(in[0], buf, 1024);
if (wyn > 0) {
char aa[1024];
write(1, buf, wyn);
fsync(1);
}
}
}
return (0);
}
a1.cpp
#include <cstdlib>
#include <unistd.h>
#include "stdio.h"
using namespace std;
/*
*
*/
int main(int argc, char** argv) {
while(true){
printf("example text\n");
usleep(100000);
}
return 0;
}

Can't invoke g++ with redirected stdout

I'm looking to invoke g++ and get the output. Here's my code:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <boost/optional.hpp>
#include <vector>
#include <string>
namespace Util
{
template<typename T>
using optional = boost::optional<T>;
}
namespace Wide
{
namespace Driver
{
struct ProcessResult
{
std::string std_out;
int exitcode;
};
ProcessResult StartAndWaitForProcess(std::string name, std::vector<std::string> args, Util::optional<unsigned> timeout);
}
}
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <fcntl.h>
Wide::Driver::ProcessResult Wide::Driver::StartAndWaitForProcess(std::string name, std::vector<std::string> args, Util::optional<unsigned> timeout) {
int filedes[2];
pipe(filedes);
pid_t pid = fork();
if (pid == 0) {
while ((dup2(filedes[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
auto fd = open("/dev/null", O_RDWR);
while ((dup2(fd, STDIN_FILENO) == -1) && (errno == EINTR)) {}
//freopen("/dev/null", "rw", stdin);
//freopen("/dev/null", "rw", stderr);
//close(filedes[1]);
close(filedes[0]);
std::vector<const char*> cargs;
cargs.push_back(name.c_str());
for (auto&& arg : args)
cargs.push_back(arg.c_str());
cargs.push_back(nullptr);
execv(name.c_str(), const_cast<char* const*>(&cargs[0]));
}
std::string std_out;
close(filedes[1]);
char buffer[4096];
while (1) {
ssize_t count = read(filedes[0], buffer, sizeof(buffer));
if (count == -1) {
if (errno == EINTR) {
continue;
} else {
perror("read");
exit(1);
}
} else if (count == 0) {
break;
} else {
std_out += std::string(buffer, buffer + count);
}
}
close(filedes[0]);
int status;
ProcessResult result;
result.std_out = std_out;
waitpid(pid, &status, 0);
if (!WIFEXITED(status))
result.exitcode = 1;
else {
result.exitcode = WEXITSTATUS(status);
if (result.exitcode != 0) {
std::cout << name << " failed with code " << result.exitcode << "\n";
}
}
return result;
}
int main()
{
auto r = Wide::Driver::StartAndWaitForProcess("g++", { "-std=c++14", "main.cpp" }, 150);
std::cout << r.std_out << "!!!!\n!!!!\n" << r.exitcode << "\n";
}
The output:
read: Bad file descriptor
g++ failed with code 1
!!!!
!!!!
1
Just invoke g++ main.cpp -std=c++14 && ./a.out.
I've used strace but it doesn't really give any more interesting details- the process runs, then fork/exec, then the above error. I can invoke other processes with the above code so I don't know what's so different about g++. I can invoke GCC with popen without problems so I don't know what's so different here.
The error here is really not very helpful. How can I invoke g++ and get the output?
The problem here is that you call execv which requires a full path to the executable as its first argument.
What you need is execvp which uses the contents of the PATH environment variable to find the executable, and thus only requires a name like g++.