Simplistic way to send data to another process (win)? - c++

Suppose you are developing two application for the windows platform (A and B).
The platform/system is Windows (Windows 10 if that matters)
How can you send some piece of information to B from A if you are only allowed to work at the c++ language level (that is: including the standard libraries and STL) ? This rules out any third party libraries.
I'm trying to avoid the system API as it usually involves a healthy amount of c-like programming (and therefore is not suited for my purpose).
In this particular scenario both processes are running continuously and the sending happens due to some outside event (if it matters) - so some kind of sync is probably needed.
Possible solutions under consideration:
Using files, via std::ofstream and std::ifstream could be a possible solution (albeit a crude one) ? - but how can sync'ing be achieved then ?
Even redirecting STDOUT to STDIN could be fine - especially if there is some simple way to set this up (eg. one-liner on command line to start - powershell could be a possibility if needed)

A solution involving transfer via a datafile (this uses std::filesystem::rename as a way of sync'ing or you could say avoid it):
a.exe (writer)
#include <filesystem>
auto tmpfile = std::filesystem::temp_directory_path() / "some_uuid.txt";
auto datafile = std::filesystem::temp_directory_path() / "data.txt";
std::ofstream(tmpfile) << "hello" << std::endl;
std::filesystem::rename(tmpfile, datafile);
b.exe (reader)
auto datafile = std::filesystem::temp_directory_path() / "data.txt";
while (!std::filesystem::exists(datafile)) {
;//we have nothing else to do ?
}
std::ifstream input(data);
//read input etc.

Related

Transferring data between executables

I have two executables written in C++ on Windows. I generate some data in one, and want to call the other executable to process this data. I could write the data out to a file then read it in the other executable, but that seems rather expensive in terms of disk I/O. What is a better way of doing this? It seems like a simple enough question but google just isn't helping!
Let's say the data is around 100MB, and is generated in its entirety before needing to be sent (i.e. no streaming is needed).
Answers that work when mixing 32 bit and 64 bit processes gain bonus points.
If your processes can easily write to and read from file, just go ahead. Create the file with CreateFile and mark it as temporary & shareable. Windows uses this hint to delay physical writes, but all file semantics are still obeyed. Since your file is only 100 MB and actively in use, Windows is almost certainly able to keep its contents fully in RAM.
You can use Boost.MPI. It is from Boost, which has high quality standard, and the code sample seems pretty explicit:
http://www.boost.org/doc/libs/1_53_0/doc/html/mpi/tutorial.html#mpi.point_to_point
// The following program uses two MPI processes to write "Hello, world!"
// to the screen (hello_world.cpp):
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
if (world.rank() == 0) {
world.send(1, 0, std::string("Hello"));
std::string msg;
world.recv(1, 1, msg);
std::cout << msg << "!" << std::endl;
} else {
std::string msg;
world.recv(0, 0, msg);
std::cout << msg << ", ";
std::cout.flush();
world.send(0, 1, std::string("world"));
}
return 0;
}
Assuming you only want to go "one direction" (that is, you don't need to get data BACK from the child process), you could use _popen(). You write your data to the pipe and the child process reads the data from stdin.
If you need bidirectional flow of data, then you will need to use two pipes, one as input and one as output, and you will need to set up a scheme for how the child process connects to those pipes [you can still set up the stdin/stdout to be the data path, but you could also use a pair of named pipes].
A third option is a shared memory region. I've never done this in Windows, but the principle is pretty much the same as what I've used in Linux [and many years back in OS/2]:
1. Create a memory region with a given name in your parent process.
2. The child process opens the same memory region.
3. Data is stored by parent process and read by child process.
4. If necessary, semaphores or similar can be used to signal completion/results ready/etc.

printing to a network printer using fstream c++ in mac

I wish to print some text directly to a network printer from my c++ code (I am coding with xcode 4). I do know that everything on unix is a file and believe that it would not be impossible to redirect the text using fstream method in c++ to the printer device file. The only problem is I don't know the device file in /dev associated with my network printer.
Is it possible to achieve printing using fstream method? Something like
std::fstream printFile;
printFile.open("//PATH/TO/PRINTER/DEV", std::ios::out);
printFile << "This must go to printer" << std::endl;
printFile.close();
And, if so
How to obtain the file in /dev corresponding to a particular printer?
Thanks in advance,
Nikhil
Opening and writing directly to a file used to be possible back in the days of serial printers; however, this is not the approach available today.
The CUPS daemon provides print queuing, scheduling, and administrative interfaces on OS X and many other Unix systems. You can use the lp(1) or lpr(1) commands to print files. (The different commands come from different versions of print spoolers available in Unix systems over the years; one was derived from the BSD-sources and the other derived from the AT&T sources. For compatibility, CUPS provides both programs.)
You can probably achieve something like you were after with popen(3). In shell, it'd be something like:
echo hello | lp -
The - says to print from standard input.
I haven't tested this, but the popen(3) equivalent would probably look like this:
FILE *f = popen("lp -", "w");
if (!f)
exit(1);
fprintf(f, "output to the printer");
I recommend testing some inputs at the shell first to make sure that CUPS is prepared to handle the formatting of the content you intend to send. You might need to terminate lines with CRLF rather than just \n, otherwise the printer may "stair-step" the output. Or, if you're sending PDF or PS or PCL data, it'd be worthwhile testing that in the cheapest possible manner to make sure the print system works as you expect.

flock-ing a C++ ifstream on Linux (GCC 4.6)

context
I'm slowly writing a specialized web server application in C++ (using the C onion http server library and the JSONCPP library for JSON serialization, if that matters)., for a Linux system with GCC 4.6 compiler (I don't care about portability to non Linux systems, or to GCC before 4.5 or to Clang before 3.0).
I decided to keep the user "database" (there will be very few users, probably one or two, so performance is not a concern, and O(n) access time is acceptable) in JSON format, probably as a small array of JSON objects like
{ "_user" : "basile" ;
"_crypasswd" : "XYZABC123" ;
"_email" : "basile#starynkevitch.net" ;
"firstname" : "Basile" ;
"lastname" : "Starynkevitch" ;
"privileges" : "all" ;
}
with the convention (à la .htpasswd) that the _crypasswd field is the crypt(3) "encryption" of the user password, salted by the _user name;
The reason I want to describe users by Json objects is that my application might add (not replace) some JSON fields (like e.g. privileges above) in such Json objects describing users. I'm using JsonCpp as a Json parsing library for C++. This library wants an ifstream to be parsed.
So I am reading my password file with
extern char* iaca_passwd_path; // the path of the password file
std::ifstream jsinpass(iaca_passwd_path);
Json::Value jpassarr;
Json::Reader reader;
reader.parse(jsinpass,jpassarr,true);
jsinpass.close();
assert (jpassarr.isArray());
for (int ix=0; ix<nbu; ix++) {
const Json::Value&jcuruser= jpassarr[ix];
assert(jcuruser.isObject());
if (jcuruser["_user"].compare(user) == 0) {
std::string crypasswd = jcuruser["_crypasswd"].asString();
if (crypasswd.compare(crypted_password(user,password)) == 0) {
// good user
}
}
}
question
Obviously, I want to flock or lockf the password file, to ensure that only one process is reading or writing it. To call these functions, I need to get the file descriptor (in Unix parlance) of the ifstream jsinpass. But Google gives me mostly Kreckel's fileno (which I find complete, but a bit insane) to get the file descriptor of an std::ifstream and I am not sure that the constructor won't pre-read some of it. Hence my question:
how can I lock a C++ ifstream (Linux, GCC 4.6) ?
(Or do you find some other way to tackle that issue?)
Thanks
My solution to this problem is derived from this answer: https://stackoverflow.com/a/19749019/5899976
I've only tested it with GCC 4.8.5.
#include <cstring> // for strerror()
#include <iostream> // for std::cerr
#include <fstream>
#include <ext/stdio_filebuf.h>
extern "C" {
#include <errno.h>
#include <sys/file.h> // for flock()
}
// Atomically increments a persistent counter, stored in /tmp/counter.txt
int increment_counter()
{
std::fstream file( "/tmp/counter.txt" );
if (!file) file.open( "/tmp/counter.txt", std::fstream::out );
int fd = static_cast< __gnu_cxx::stdio_filebuf< char > * const >( file.rdbuf() )->fd();
if (flock( fd, LOCK_EX ))
{
std::cerr << "Failed to lock file: " << strerror( errno ) << "\n";
}
int value = 0;
file >> value;
file.clear(); // clear eof bit.
file.seekp( 0 );
file << ++value;
return value;
// When 'file' goes out of scope, it's closed. Moreover, since flock() is
// tied to the file descriptor, it gets released when the file is closed.
}
You might want to use a separate lockfile rather than trying to get the descriptor from the ifstream. It's much easier to implement, and you could probably wrap the ifstream in a class that automates this.
If you want to ensure atomic open/lock, You might want to construct a stream using the method suggested in this SO answer, following open and flock
A deficiency with the filestream API is that you cannot (at least not easily) access the file descriptor of an fstream (see here and here, for example). This is because there is no requirement that fstream is implemented in terms of FILE* or file descriptors (though in practice it always is).
This is also required for using pipes as C++ streams.
Therefore the 'canonical' answer (as implied in the comments to the question) is:
create a stream buffer (derived from std::basic_streambuf) that uses Posix and C stdio I/O functions (i.e open etc) and thus gives access to the file descriptor.
Create your own 'LockableFileStream' (derived from std::basic_iostream) using your stdio based stream buffer instead of std::streambuf.
You may now have a fstream like class from which you may gain access to the file descriptor and thus use fcntl (or lockf) as appropriate.
There are a few libraries which provide this out of the box.
I had thought this was addressed partly now that we've reached C++17 but I can't find the link so I must have dreamed it.
Is the traditional unix-y solution of relying on the atomicity of rename() unacceptable?
I mean, unless your JSON serialization format supports in-place update (with a transaction log or whatever), then updating your password database entails rewriting the entire file, doesn't it? So you might as well write it to a temporary file, then rename it over the real name, thus ensuring that readers read a consistent entry? (Of course, in order for this to work each reader must open() the file each time it wants to access a DB entry, leaving the file open doesn't cut it)

How to enable sharing of open files in C++?

My Code:
std::ofstream m_myfile,
m_myfile.open ("zLog.txt");
m_myfile << "Writing this to a file " << " and this " << endl;
when this C++ Program runs, I have another program that needs to read this file. The problem is that the file is locked by C++ and I cannot read it from the other program. I know there is something I have to do where I write the code someway in the C++ Program where it allows sharing. Can someone write exactly what I need. I have googled this to death and still cannot get this to work.
Some people say close the file, before the other program reads it. I cannot do this, the file needs to be open.
You need to open the file with sharing enabled. Use the following overload of the open method:
void open(const char *szName, int nMode = ios::out, int nProt = filebuf::openprot);
and pass the appropriate share mode as nProt:
filebuf::sh_compat: Compatibility share mode
filebuf::sh_none: Exclusive mode; no sharing
filebuf::sh_read: Read sharing allowed
filebuf::sh_write: Write sharing allowed
There is also an overload of the ofstream constructor that takes the same arguments.
The sharing is going to be controlled at the OS level. So you need to look at the API for your OS and figure out how to turn read-write sharing on.
Note: you still probably won't get the results you want because there will be caching and buffering issues and what you think was written to the file may not actually be there.
If you want to share information between two processes, use named pipes or sockets. Both are available on just about every OS.
Use filebuf::sh_write while opening the file.
Other option is to use sockets. Check out this stackoverflow question: Is there a way for multiple processes to share a listening socket?

Passing information between two seperate programs

I want to pass a value of an input variable in my program lets say#1 to another program #2 and i want #2 to print the data it got to screen, both are needed to be written in c++. The this will be on Linux.
Depending on the platform there are a number of options available. What you are trying to do is typically called inter-process communication (IPC).
Some options include:
Sockets
Pipes
Queues
Shared Memory
What is easiest is probably dependent on the platform youa are using.
As always, there is a Boost library for that (God, I like Boost).
Nic has covered all the 4 that I wanted to mention (on the same machine):
Sockets
Pipes
Queues
Shared Memory
If writing system calls is troublesome for you, you may want to use the following libraries:
Boost http://www.boost.org/
Poco http://pocoproject.org/blog/
Nokia Qt http://qt.nokia.com/
Something you can read from Qt portable IPC: only QSharedMemory?
If effeciency is not prime concern then use normal file i/o.
else go for IPC to do so.
As far as Windows is concern you have following options :
Clipboard ,
COM ,
Data Copy ,
DDE ,
File Mapping ,
Mailslots ,
Pipes ,
RPC ,
Windows Sockets
For Linux , use can use Name Pipes(efficient) or sockets.
If you're on Windows, you can use Microsoft Message Queueing. This is an example of queue mentioned previously.
If the data to be passed is just a variable, then one of the option is to set it as Environment Variable [ Var1 ] by program #1 and access it, in Program #2 [ if both are running on same env/machine ]. Guess this will be the easiest one, instead of making it complex, by using IPC/socket etc.
I think most of the answers have address the common IPC mechanisms. I'd just like to add that I would probably go for sockets because it's fairly most standard across several platforms. I decided to go for that when I needed to implement IPC that worked both on Symbian Series 60 and Windows Mobile.
The paradigm is straightforward and apart from a few platform glitches, the model worked the same for both platforms. I would also suggest using Protocol Buffers to format the data you send through. Google uses this a lot in its infrastructure. http://code.google.com/p/protobuf/
DBUS
QtDbus
DBus-mm
In response to your comment to Roopesh Majeti's answer, here's a very simple example using environment variables:
First program:
// p1.cpp - set the variable
#include <cstdlib>
using namespace std;;
int main() {
_putenv( "MYVAR=foobar" );
system( "p2.exe" );
}
Second program:
// p2.cpp - read the variable
#include <cstdlib>
#include <iostream>
using namespace std;;
int main() {
char * p = getenv( "MYVAR" );
if ( p == 0 ) {
cout << "Not set" << endl;
}
else {
cout << "Value: " << p << endl;
}
}
Note:
there is no standard way of setting an environment variable
you will need to construct the name=value string from the variable contents
For a very dirt and completely nonprofessional solution you can do it like me.
Save the variable in to a file and then read it (in an infinite loop every x time) with the other program.
fsexample.open("F:/etc etc ...");
fsexample >> data1 >> data2; // etc etc
and on the other side
fsexample.open("F:/etc etc ...");
fsexample << data1 << data2; // etc etc
The trick is that F is a virtual drive created with ramdisk so it is fast
and heavy-duty proof.
You could have problem of simultaneous access but you can check it with
if (!fsexample.is_open()) {
fsexample_error = 1;
}
and retry on failure.