I have the following server (C++):
#include <nng/nng.h>
#include <nng/protocol/pubsub0/pub.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <unistd.h>
void
fatal(const char *func, int rv)
{
fprintf(stderr, "%s: %s\n", func, nng_strerror(rv));
}
int main(int argc, char* argv[]){
nng_socket sock;
int rv;
std::string url = "tcp://0.0.0.0:" + std::to_string(5563);
if ((rv = nng_pub0_open(&sock)) != 0) {
fatal("nng_pub0_open", rv);
}
if ((rv = nng_listen(sock, url.c_str(), NULL, 0)) < 0) {
fatal("nng_listen", rv);
}
while(1){
std::string msg = std::string("msg");
//if ((rv = nng_send(sock, (void*)frame, bpp * nImgW * nImgH, 0)) != 0) {
if ((rv = nng_send(sock, (void*)msg.c_str(), 3, 0)) != 0) {
fatal("nng_send", rv);
}else{
std::cout << "Frame Sent... "<< std::endl;
}
sleep(1);
}
}
And the following client (python):
import pynng
from pynng import Pub0, Sub0, Timeout
cam_path = "tcp://127.0.0.1:5563"
with Sub0(dial=cam_path,recv_timeout=2000, topics=b'') as sub:
sub.recv_max_size = 0 #recieve msg of any size
while(1):
try:
print("waiting for msg")
img = sub.recv()
print(img)
except pynng.exceptions.Timeout as e:
print('Timed out, retrying...')
I dont understand why no messages ever arrive to the client. I have set topics and recv_max_size but still no messages arrives at the client.
What am I doing wrong here now?
Q : "What am I doing wrong here now?"
You happened to blindly assume that things happen in a very way your code does not attempt to validate. Old assembler wolves used to state # ASSUME NOTHING before they ever started a code :o)
Pieter Hintjens', the famous AMQP / ZeroMQ evangelisation Guru (an older brother of the nanomsg / nng ) uses explicit POSACK-s from assert-s :
if ( ( aRetCODE = nng_pub0_open( &sock ) ) != 0 ) {
fatal( "nng_pub0_open",
aRetCODE );
}
assert( aRetCODE == 0 && "EXC: Pub0 socket failed to instantiate" );
if ( ( aRetCODE = nng_listen( sock, url.c_str(), NULL, 0 ) ) < 0 ) {
fatal( "nng_listen",
aRetCODE );
}
assert( aRetCODE == 0 && "EXC: Pub0 socket failed to .listen()" );
Python has also a similar assert-tool for explicit POSACK-checks, so worth polishing the code-robustness using them as Pieter Hintjens has made Martin Sustrik to do so wherever you read the API :o)
assert rc == 0, "INF: some condition was not met for ( %r )" % someVariableNAME
Happy using nng / pynng for your Projects!
Related
I have a c function that publish data to a c++ subscriber, now I want to migrate this c function to Python:
void setup_msg_publish() {
int r;
zmqcontext = zmq_ctx_new();
datasocket = zmq_socket(zmqcontext, ZMQ_PUB);
r = zmq_bind(datasocket, "tcp://*:44000");
if (r == -1) {
printf(zmq_strerror(errno));
}
}
void publishdata(int x, int y) {
if (datasocket == 0) {
setup_msg_publish();
}
zmq_data zd;
zd.msgType = int 0;
zd.x = x;
zd.y = y;
size_t len = sizeof(zd);
int res = zmq_send(datasocket, &zd, len, NULL);
assert(res == len);
}
I've tried to implement this in Python:
import zmq
import pickle
from collections import namedtuple
Data = namedtuple("Data", "msgType x y")
def send_zmq():
data = Data("0", "1", "2")
msg = pickle.dumps(data)
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:44000")
socket.send(msg)
For debug purposes I can recive the data with Python like this:
import zmq
import pickle
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://127.0.0.1:44000")
while True:
message = socket.recv()
data = pickle.loads(message)
print(data)
But I don't receive anything in my c++ code (it just prints no data):
#include "View.h"
#include <iostream>
#include <thread>
#include <chrono>
View::View() :
viewSubscriber(zmqcontext, ZMQ_SUB)
{
unsigned _int16 msgType = 0;
viewSubscriber.connect("tcp://127.0.0.1:44000");
//viewSubscriber.setsockopt(ZMQ_SUBSCRIBE, &msgType, sizeof(msgType));
viewSubscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
std::cout << msgType;
}
void View::run() {
using namespace std;
bool received_view_data = false;
bool checkForMore = true;
zmq_view data;
while (checkForMore) {
zmq::message_t msg;
//cout << &msg;
if (viewSubscriber.recv(&msg, ZMQ_NOBLOCK)) {
received_view_data = true;
memcpy(&data, msg.data(), sizeof(data));
cout << &data.x;
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
cout << "no data \n";
}
}
}
int main(){
View *app = new View();
app -> run();
return 0;
}
Any ideas what to fix so I receive the data in the namedTuple on the c++ side? Could it be that the c++ "needs to know more" about the type of each attribute of the namedTuple (if that is the case how do I specify whether the data is a double or int etc?)?
The solution was found after testing to go from C++ -> Python thank you J_H for the idea. Instead of using a namedtuple a packed struct was used.
import zmq
import struct
def send_zmq():
struct_format = 'Idd'
msg_type = 0
x = 1.0
y = 1.0
msg = struct.pack(struct_format, msg_type, x, y)
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:44000")
socket.send(msg)
I have already checked out bind() return EINVAL and that is not the issue here. Please read through before you get furious about duplication.
I am trying to connect to wpa_supplicant. Basically I'm trying to achieve this using C++:
import os
import select
import socket
interface = "wlp4s0"
wpa_send_path = "/run/wpa_supplicant/"+interface
wpa_recv_path = "/tmp/wpa_ctrl_{pid}-{count}".format(pid=os.getpid(), count=1)
soc = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
soc.bind(wpa_recv_path)
soc.connect(wpa_send_path)
print("> PING")
soc.send(b"PING")
print("<", soc.recv(4096).decode().strip())
from https://gist.github.com/artizirk/cd3980c8ff870eb0bfce68bc26a2676b
And I have done what I wanted but using plain C++. This is the code:
#include <iostream>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#define PATH "/run/wpa_supplicant/wlp4s0"
char path[100] = "/tmp/wpa_ctrl_";
int main(void) {
int ctrl_socket;
char buffer[1024];
struct sockaddr_un socket_addr, send_addr;
memset(&socket_addr, 0, sizeof(struct sockaddr_un));
memset(&send_addr, 0, sizeof(struct sockaddr_un));
socket_addr.sun_family = AF_UNIX;
send_addr.sun_family = AF_UNIX;
strcpy(send_addr.sun_path, PATH);
strcat(path, std::to_string(getpid()).c_str());
strcat(path, "-1");
strcat(socket_addr.sun_path, path);
if ((ctrl_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
std::cerr << "Error creating socket!" << std::endl;
std::exit(EXIT_FAILURE);
}
/* Unlink if already bound */
unlink(socket_addr.sun_path);
if ((connect(ctrl_socket, (struct sockaddr *)&send_addr, SUN_LEN(&send_addr))) == -1) {
std::cerr << "Error connecting to socket!" << std::endl;
std::exit(EXIT_FAILURE);
}
if (bind(ctrl_socket, (const struct sockaddr *)&socket_addr, offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1) == -1) {
perror("Error");
exit(EXIT_FAILURE);
}
send(ctrl_socket, "PING", 5, 0);
recv(ctrl_socket, buffer, 1024, 0);
std::cout << buffer << std::endl;
close(ctrl_socket);
return 0;
}
This code works fine. But when I do it in Qt, bind() always return EINVAL i.e Invalid Arguments. Here's that code:
WPASupplicantControl::WPASupplicantControl(std::string wlan_interface_name)
:wpa_send_ctrl_iface(WPA_SEND_CTRL_IFACE_PREFIX + QString::fromStdString(wlan_interface_name)),
wpa_recv_ctrl_iface(
WPA_RECV_CTRL_IFACE_PREFIX +
QString::fromStdString(std::to_string(getpid())) +
"-1"
)
{
struct sockaddr_un send_address, recv_address;
send_address.sun_family = AF_UNIX;
recv_address.sun_family = AF_UNIX;
memset(&send_address, 0, sizeof (send_address));
memset(&recv_address, 0, sizeof (recv_address));
strncpy(send_address.sun_path, wpa_send_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
strncpy(recv_address.sun_path, wpa_recv_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
if ((wpa_control_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
qCritical() << "socket() failed!";
exit(EXIT_FAILURE);
}
/* Attatch to sending and receiving control interfaces */
if (connect(wpa_control_socket, (const struct sockaddr *)&send_address, SUN_LEN(&send_address)) == -1) {
qCritical() << "Error connecting to wpa_supplicant send control iface!";
close(wpa_control_socket);
exit(EXIT_FAILURE);
}
/* Detatch if it's already bound */
unlink(recv_address.sun_path);
if (bind(wpa_control_socket, (const struct sockaddr *)&recv_address, offsetof(struct sockaddr_un, sun_path) + wpa_recv_ctrl_iface.length() + 1) == -1) {
qCritical() << "Error binding to wpa_supplicant recv control iface!";
close(wpa_control_socket);
exit(EXIT_FAILURE);
}
}
A functional dummy project to test this code is at: https://github.com/gaurav712/socket_test
I have checked all the values hundreds of times and they're all fine but still it doesn't work. It just goes upto that connect() call.
I thought I should use something Qt-specific and I found out about QLocalSocket https://doc.qt.io/qt-5/qlocalsocket.html but when I import it, Qt doesn't recognize that class. Maybe its because I'm on Qt 6.x and it is now deprecated(although I didn't find any official deprecation notice thingy). What do I do? What am I doing wrong?
Absolutely nothing to do with Qt: You do a memset to all-0 of the sockaddr structures after you've set the socket's family to AF_UNIX (which is "1" on most platforms). How should the system know you want a local socket?
strncpy will copy at most n bytes from source to dest. If there's no null char within n bytes, it's not going to copy it over. The third parameter to strncpy is usually meant to convey the length of the destination buffer.
Change this:
strncpy(send_address.sun_path, wpa_send_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
strncpy(recv_address.sun_path, wpa_recv_ctrl_iface.toStdString().c_str(), wpa_send_ctrl_iface.length());
To be this:
strncpy(send_address.sun_path,
wpa_send_ctrl_iface.toStdString().c_str(),
sizeof(send_address.sun_path) );
strncpy(recv_address.sun_path,
wpa_recv_ctrl_iface.toStdString().c_str(),
sizeof(recv_address.sun_path));
Also, as discussed in the comments, your length param to bind looks funky as well. Try it both with the above changes.
I am trying to make a messenger program (that currently has a ton of bugs so please dismiss them) and for some reason, the server wont let the clients connect. I have tried changing the port, but nothing works. I get the following error (for my client, which is in python) (this is on a mac, but I have tried the client on a windows computer, still nothing):
Traceback (most recent call last):
File "msgclient.py", line 31, in <module>
Program()
File "msgclient.py", line 8, in __init__
self.s.connect((IP, PORT))
ConnectionRefusedError: [Errno 61] Connection refused
Here is the code for the server (written in c):
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#define MAXCLIENTS 256
#define MAXMSG 269
#define PORT 9989
void forward(int clientslist[MAXCLIENTS], char* msg) {
int x;
for (x=0; x < MAXCLIENTS; x++){
send(clientslist[x], msg, sizeof(msg), 0);
}
return;
}
int main(){
int s = socket(AF_INET, SOCK_STREAM, 0);
int clients[MAXCLIENTS];
int clientcounter = 0;
fd_set socketlist, readlist;
FD_ZERO(&socketlist);
FD_SET(s, &socketlist);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
bind(s, (struct sockaddr*) &server, sizeof(server));
listen(s, MAXCLIENTS);
int clientsocket;
int i;
int rc;
int max = s;
void* msg = (char *) malloc(MAXMSG+1);
void* usr = (char *) malloc(14);
while (1){
readlist = socketlist;
select(FD_SETSIZE, &readlist, NULL, NULL, NULL);
for (i=0; i<max+1; i++){
if(FD_ISSET(i, &readlist)){
if (i == s){
clientsocket = accept(s, NULL, NULL);
FD_SET(clientsocket, &socketlist);
clients[clientcounter] = clientsocket;
clientcounter++;
rc = recv(clientsocket, usr, 10, 0);
printf("Connection received from %s\n", usr);
usr = "\0";
if (clientsocket > max+1){
max = clientsocket;
}
} else {
rc = recv(i, msg, MAXMSG, 0);
if (rc > 0){
forward(clients, msg);
} else{
close(i);
msg = "\0";
}
}
}
}
}
return 0;
}
and the client (written in python):
import socket
class Program:
def __init__(self):
IP = socket.gethostbyname(socket.gethostname())
PORT = 9989
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect((IP, PORT))
self.user = self.username()
self.s.send(bytes(self.user, "utf-8"))
while True:
received = self.s.recv(269)
received = received.decode("utf-8")
print(received)
self.enter()
def username(self):
name = str(input("Enter a username (10 character max): "))
if len(name) > 10:
print("Username is larger than 10; try again")
self.username()
return name;
def enter(self):
msg = str(input("Enter a message>> "))
if msg != "":
self.s.send(bytes(f"{self.user}>> {msg}", "utf-8"))
if __name__ == "__main__":
Program()
regarding the function:
void forward(int clientslist[MAXCLIENTS], char* msg)
and
send(clientslist[x], msg, sizeof(msg), 0);
The expression: sizeof(msg) will return a value (depending on your underlying hardware and certain compiler parameters) of 4 or 8, Not what you want. Suggest passing the actual number of bytes to transmit.
regarding the function:
void forward(int clientslist[MAXCLIENTS], char* msg)
and the statement:
return;
The return; statement is completely unnecessary. Suggest removing that statement.
regarding:
int s = socket(AF_INET, SOCK_STREAM, 0);
This statement can fail. Always check (if socket < 0) then handle the error
regarding:
server.sin_addr.s_addr = INADDR_ANY;
INADDR_ANY has the value: "0.0.0.0" which cannot be directly assigned. Suggest:
server.sin_addr.s_addr = htonl(INADDR_ANY);
OT: regarding:
bind(s, (struct sockaddr*) &server, sizeof(server));
and
listen(s, MAXCLIENTS);
These functions can fail. Always check the returned value to assure the operation was successful.
OT: regarding:
void* msg = (char *) malloc(MAXMSG+1);
and similar statements. In C, the returned type is void* which can be assigned to any pointer. Casting just clutters the code and is error prone. even this statement has an error in the cast. Suggest removing that cast.
regarding:
readlist = socketlist;
select(FD_SETSIZE, &readlist, NULL, NULL, NULL);
for (i=0; i<max+1; i++)
{
if(FD_ISSET(i, &readlist))
{
if (i == s)
{
This code sequence forces serial handling of the incoming sockets. Much better to generate a 'thread pool', then use accept() and pass the resulting client socket to an idle thread. The thread then performs all the communication with the client, then, when finishing with the client, closes the client socket.
regarding:
select(FD_SETSIZE, &readlist, NULL, NULL, NULL);
There must already be an open socket to the client, which there is none, so no communication occurs.
there may be other problems, but this should aim you in the right direction.
I would like to send over a message structure from a DLL-callback function to a python application so I can log the messages.
For this I would like to use ZeroMQ. Sadly I am unable to get the messages to python using the example provided by ZeroMQ.
DLL:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <zmq.h>
HHOOK tHook;
HMODULE hinstDLL;
void* requester;
void* context;
LRESULT CALLBACK meconnect(int code, WPARAM wParam, LPARAM lParam) {
if (code == HC_ACTION) {
LPMSG data = (LPMSG)lParam;
UINT message = data->message;
switch (message)
{
case WM_POINTERUPDATE:
if (!IS_POINTER_INCONTACT_WPARAM(wParam))
break;
case WM_POINTERDOWN:
case WM_POINTERUP:
POINTER_INFO pointerInfo = {};
GetPointerInfo(GET_POINTERID_WPARAM(wParam), &pointerInfo);
int request_nbr;
for (request_nbr = 0; request_nbr != 10; request_nbr++) {
char buffer[10];
printf("Sending Hello %d…\n", request_nbr);
zmq_send(requester, data, 5, 0);
zmq_recv(requester, buffer, 10, 0);
printf("Received World %d\n", request_nbr);
}
}
}
return(CallNextHookEx(tHook, code, wParam, lParam));
}
extern "C" __declspec(dllexport) BOOL ConnectServer() {
printf("Connecting to hello world server…\n");
static void* context = zmq_ctx_new();
static void* requester = zmq_socket(context, ZMQ_REQ);
zmq_connect(requester, "tcp://127.0.0.1:5555");
printf("connected");
return TRUE;
}
extern "C" __declspec(dllexport) BOOL DisconnectServer() {
zmq_close(requester);
zmq_ctx_destroy(context);
return TRUE;
}
extern "C" __declspec(dllexport) BOOL SetHook()
{
tHook = SetWindowsHookEx(WH_GETMESSAGE, meconnect, hinstDLL, 0);
if (tHook == NULL)
return FALSE;
else
return TRUE;
}
extern "C" __declspec(dllexport) BOOL UnHook()
{
return UnhookWindowsHookEx(tHook);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hinstDLL = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Python:
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://127.0.0.1:5555")
def message_msg_loop():
while True:
# Wait for next request from client
message = socket.recv()
print("Received request: %s" % message)
# Do some 'work'
time.sleep(1)
# Send reply back to client
socket.send(b"World")
def pointer_msg_loop():
global lib
lib = cdll.LoadLibrary(r'C:\Users\Braun\Documents\BA_Thesis\ba-oliver-braun-logging-tool-code\MessagesDll\x64\Release\HOOKDLL.dll')
print(lib)
res = lib.ConnectServer()
res = lib.SetHook()
pythoncom.PumpMessages()
res = lib.UnHook()
Basically my plan was to detect a certain event through windows messages and pass the message structure from the DLL-callback over to the server in Python, so I can handle the data there and put them into a log file. It does not seem to work though.
In case one has never worked with ZeroMQ,one may here enjoy to first look at "ZeroMQ Principles in less than Five Seconds"before diving into further details
Simplicity helps us start,rather than remain headbanging into Complexity First
Best avoid all the complexities :
- set .setsockopt( zmq.LINGER, 0 ) # ALWAYS, never know what version will try to join the Club
- prototype with PUSH/PULL(it a) meets the spec.+b) does not block in a mutual deadlock as all REQ/REP do )
- never share a socket ( yes, the requester ought be a private, non-shared instance )
- always read-in and assert-eval the return-codes from the ZeroMQ API calls ( detect many issues on-spot )
Can you POSACK / prove the both of the module-level declarations
...
void* requester;
void* context;
LRESULT CALLBACK meconnect(...) {...}
...
actually work as expected, or does the ConnectServer(){...}'s internal, in-scope declarations mask both of these globals ?
extern "C" __declspec(dllexport) BOOL ConnectServer() {
printf("Connecting to hello world server…\n");
static void* context = zmq_ctx_new(); // shadows out void* context
static void* requester = zmq_socket(context, ZMQ_REQ); // shadows out void* requester
zmq_connect(requester, "tcp://127.0.0.1:5555");
printf("connected");
return TRUE;
}
I have managed to get C code calling Python scripts happily on Unix using PIPES within the C code. I now need to do the same on Windows.
Essentially I would like to write scripts in different scripting languages like Python / Lua etc on Windows and be able to execute them using STDIN / STDOUT etc.
I have been looking at the "CreateProcess" call at:
http://msdn.microsoft.com/en-us/library/ms682425(VS.85).aspx
and although I can get it to work with a "child written in C", I cannot get it to call a Python script.
Below is the "parent / sender code" on my windows box:
#include<windows.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "User32.lib")
void DisplayError(char *pszAPI);
void readFromPipe(HANDLE hPipeRead);
void createChildProcess(char *commandLine,
HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr);
DWORD WINAPI writeToPipe(LPVOID lpvThreadParam);
HANDLE hChildProcess = NULL;
HANDLE hStdIn = NULL;
BOOL bRunThread = TRUE;
char *inputStream;
int main(int argc, char *argv[]){
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
HANDLE hInputWriteTmp,hInputRead,hInputWrite;
HANDLE hErrorWrite;
HANDLE hThread;
DWORD ThreadId;
SECURITY_ATTRIBUTES sa;
int streamLen;
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
return 1;
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
return 1;
if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
return 1;
if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
GetCurrentProcess(),
&hOutputRead,
0,FALSE,
DUPLICATE_SAME_ACCESS))
return 1;
if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
GetCurrentProcess(),
&hInputWrite,
0,FALSE,
DUPLICATE_SAME_ACCESS))
return 1;
if (!CloseHandle(hOutputReadTmp)) return 1;;
if (!CloseHandle(hInputWriteTmp)) return 1;;
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE )
return 1;
if (argc == 2){
createChildProcess(argv[1], hOutputWrite,hInputRead,hErrorWrite);
}else{
puts("No process name / input stream specified\n");
return 1;
}
if (!CloseHandle(hOutputWrite)) return 1;;
if (!CloseHandle(hInputRead )) return 1;;
if (!CloseHandle(hErrorWrite)) return 1;;
hThread = CreateThread(NULL,0,writeToPipe,
(LPVOID)hInputWrite,0,&ThreadId);
if (hThread == NULL)
return 1;;
readFromPipe(hOutputRead);
if (!CloseHandle(hStdIn))
return 1;
bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
return 1;;
if (!CloseHandle(hOutputRead)) return 1;;
if (!CloseHandle(hInputWrite)) return 1;;
}
void createChildProcess(char *commandLine,
HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr){
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hChildStdOut;
si.hStdInput = hChildStdIn;
si.hStdError = hChildStdErr;
if (!CreateProcess(NULL,commandLine,NULL,NULL,TRUE,
NULL,NULL,NULL,&si,&pi))
hChildProcess = pi.hProcess;
if (!CloseHandle(pi.hThread)) return 1;;
}
void readFromPipe(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;
while(TRUE)
{
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
return 1; // Something bad happened.
}
if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
return 1;;
}
}
DWORD WINAPI writeToPipe(LPVOID lpvThreadParam)
{
CHAR read_buff[256];
DWORD nBytesRead,nBytesWrote;
HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
while (bRunThread){
nBytesRead = 21;
strncpy(read_buff, "hello from the paren\n",21);
read_buff[nBytesRead] = '\0';
if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL)){
if (GetLastError() == ERROR_NO_DATA)
break; //Pipe was closed (normal exit path).
else
return 1;;
}
}
return 1;
}
Quite a bit of the above code is "hardcoded" just for testing purposes...essentially I passing some text like "hello from the paren" to be sent to a "child.exe"....
Here is the code for the child.c...a simple ECHO of what is sent to it
#include<windows.h>
#include<stdio.h>
#include<string.h>
void main (){
CHAR szInput[1024];
ZeroMemory(szInput,1024);
gets(szInput);
puts(szInput);
fflush(NULL);
}
To run the app I send "CallSubProcess.exe Child.exe" and it works 100%
Next I want to change "child.c" to be a PYTHON SCRIPT...
import sys
if __name__ == "__main__":
inStream = sys.stdin.read()
outStream = inStream
sys.stdout.write(outStream)
sys.stdout.flush()
So how can I change the CreateProcess call to execute this script?
if (!CreateProcess("C:\\Python26\\python.exe", "echo.py",NULL, NULL,FALSE, 0,NULL,NULL,&si,&pi)){
But it never works.
Any ideas how I can get this to work? Any help will be greatly appreciated.
My application posts a string to a python script, and the python script posts the string back to the c
application. It works well.
//c code
#pragma comment(lib, "json_vc71_libmtd.lib")
#include <windows.h>
#include <iostream>
#include <io.h>
#include "./json/json.h"
using namespace std;
DWORD WINAPI threadproc(PVOID pParam);
HANDLE hRead, hWrite, hRead1, hWrite1;
int main()
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if (!CreatePipe(&hRead, &hWrite, &sa, 0)){
::MessageBox(NULL, L"can't create pipe", L"error", MB_OK);
return -1;
}
if (!CreatePipe(&hRead1, &hWrite1, &sa, 0)){
::MessageBox(NULL, L"can't create pipe1", L"error", MB_OK);
return -1;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
GetStartupInfo(&si);
si.cb = sizeof(STARTUPINFO);
si.hStdError = hWrite;
si.hStdOutput = hWrite;
si.hStdInput = hRead1;
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
WCHAR szCmdLine[] = L"\"D:\\tools\\python\\python.exe\" D:\\code\\test\\pipeCallCore\\pipeCallCore\\json_wraper.py";
if (!CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)){
::MessageBox(NULL, L"can't create process", L"error", MB_OK);
return -1;
}
CloseHandle(hWrite);
CloseHandle(hRead1);
const int cBufferSize = 4096;
char buffer[cBufferSize] = {0};
DWORD bytes;
int i = 0;
while (true){
cout << "come !" << endl;
ZeroMemory(buffer, sizeof(buffer));
sprintf(buffer, "{\"write\":%d}\n", i ++);
if (NULL == WriteFile(hWrite1, buffer, strlen(buffer), &bytes, NULL)){
::MessageBox(NULL, L"write file failed!", L"error", MB_OK);
break;
}
ZeroMemory(buffer, sizeof(buffer));
if (NULL == ReadFile(hRead, buffer, cBufferSize - 1, &bytes, NULL)){
::MessageBox(NULL, L"readfile failed", L"error", MB_OK);
return -1;
}
cout <<"yes " << buffer << endl;
Sleep(2000);
}
return 0;
}
//python code
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
while True:
try:
s = sys.stdin.readline()
sys.stdout.write(s)
sys.stdout.flush()
except EOFError, KeyboardInterrupt:
break
Maybe
if (!CreateProcess("C:\\Python26\\python.exe",
"echo.py 'hello from parent'",
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
CreateProcess is kind of tricky to use.
From the MSDN documentation:
If both lpApplicationName and lpCommandLine are non-NULL, ... lpApplicationName specifies the module to execute, and ... lpCommandLine specifies the command line.... Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.
To avoid the weirdness, I recommend always passing NULL for the first argument and to pass the full command-line as the second:
CreateProcess(NULL, "\"C:\\Python26\\python.exe\" echo.py", ...);