CreateNamedPipe()
-
Re-design of a process launched with re-directed STD streams. Process A creates two named pipes. One to write to the input of launched process B and one to read from process B. Standard stuff. Process B launches process C and D and E etc.. In that order and each one runs synchronously. So, only one sub-process is active at any one time. Process' C,D,E in turn connect to process A through the CreateFile() function - again standard stuff. Now, the first pass runs just fine - process C reads and writes records from/to A and then ends. Then process D starts - but there is nothing in the pipe. Process A puts stuff in the pipe - it is active all the time - (until process B terminates), then it deals with process E and so on .. I know that this a bit vague interms of detial - but I have tried every combination of CreateNamedPipe/ConnectNamedPipe/DisconnectNamedPipe on the server side and PeekNamePipe/ReadFile etc on the server side - with pipe busy and pipe closed returncodes. If anyone has an example or knows of where I can get some idea of how to design a server side mechanism that lets multiple synchronous clients connect in-turn then you would be my friend. I guess that I am missing something very simple - I hope.
Are you closing the pipe handle with
CloseHandle()
in process C before process D tries to connect?The difficult we do right away... ...the impossible takes slightly longer.
-
OK, perhaps if you could show your main server loop code, it might help.
The difficult we do right away... ...the impossible takes slightly longer.
Hiya. The following code is bit of a mess - cos - I dont know how to submit stuff in a web friendly way - sorry about that - but if you can spot where I am going wrong in-terms of process control - especially in this server stuff - great - below - note - the peek before the read is for good reson! UINT ReadWorker( LPVOID a_pParam ) { // Get the pipeline and stage number for this worker. CCallpipe *p = ( CCallpipe * )a_pParam; #ifdef _PIPE_DIAG_MESSAGE_ CString szPrefix; szPrefix.Format( "CCallpipe::ReadWorker(%d,%d)", p->Pipeline(), p->Stage() ); CApplMessage cons( true, true, ( LPCTSTR )szPrefix ); cons.Write( "Starting ReadWorker" ); #endif // _PIPE_DIAG_MESSAGE_ CHAR szReadBuffer[ _IO_BUFFSIZE_ ]; DWORD dwBytesWritten = 0; DWORD dwRecCount = 0; // Create the lock name. p->m_szLock.Format( "CALLPIPE-%.5d", p->m_dwProcId ); // Connect to the IN stage input stream pipeline. ConnectNamedPipe( p->m_hInputWrite, NULL ); // Ok, now lets read and process our input stream. for( ;; ) { // Read a record from the primary input stream. if( !p->m_pManager->PeekRecord( *p->m_pProcess, 0, &p->m_szInRecord ) ) { #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "Read of stream: %d, failed", 0 ); #endif // _PIPE_DIAG_MESSAGE_ break; } #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "I have read the following: >%s<", ( LPCTSTR )p->m_szInRecord ); #endif // _PIPE_DIAG_MESSAGE_ const char *pszRecord = ( LPCTSTR )p->m_szInRecord; do { // Copy the input record to the buffer we will pass the WriteFile(). int nIndex; for( nIndex = 0; nIndex < ( _IO_BUFFSIZE_ - 2 ) && *pszRecord; ++nIndex ) { szReadBuffer[ nIndex ] = *pszRecord; ++pszRecord; } szReadBuffer[ nIndex ] = 0; // If its the end of the record, tag on the newline character. if( !*pszRecord ) { szReadBuffer[ nIndex ] = _NEWLINE_; ++nIndex; szReadBuffer[ nIndex ] = 0; } #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "Writing: %s", szReadBuffer ); #endif // _PIPE_DIAG_MESSAGE_ if( !WriteFile( p->m_hInputWrite, szReadBuffer, ( DWORD )nIndex, &dwBytesWritten, NULL ) ) { if( GetLastError() == ERROR_NO_DATA ) { #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "The pipe is now closed!" ); #endif // _PIPE_DIAG_MESSAGE_ break; } else { DWORD dwRetCode = GetLastError(); CString szMessage;
-
Are you closing the pipe handle with
CloseHandle()
in process C before process D tries to connect?The difficult we do right away... ...the impossible takes slightly longer.
Yes
-
Hiya. The following code is bit of a mess - cos - I dont know how to submit stuff in a web friendly way - sorry about that - but if you can spot where I am going wrong in-terms of process control - especially in this server stuff - great - below - note - the peek before the read is for good reson! UINT ReadWorker( LPVOID a_pParam ) { // Get the pipeline and stage number for this worker. CCallpipe *p = ( CCallpipe * )a_pParam; #ifdef _PIPE_DIAG_MESSAGE_ CString szPrefix; szPrefix.Format( "CCallpipe::ReadWorker(%d,%d)", p->Pipeline(), p->Stage() ); CApplMessage cons( true, true, ( LPCTSTR )szPrefix ); cons.Write( "Starting ReadWorker" ); #endif // _PIPE_DIAG_MESSAGE_ CHAR szReadBuffer[ _IO_BUFFSIZE_ ]; DWORD dwBytesWritten = 0; DWORD dwRecCount = 0; // Create the lock name. p->m_szLock.Format( "CALLPIPE-%.5d", p->m_dwProcId ); // Connect to the IN stage input stream pipeline. ConnectNamedPipe( p->m_hInputWrite, NULL ); // Ok, now lets read and process our input stream. for( ;; ) { // Read a record from the primary input stream. if( !p->m_pManager->PeekRecord( *p->m_pProcess, 0, &p->m_szInRecord ) ) { #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "Read of stream: %d, failed", 0 ); #endif // _PIPE_DIAG_MESSAGE_ break; } #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "I have read the following: >%s<", ( LPCTSTR )p->m_szInRecord ); #endif // _PIPE_DIAG_MESSAGE_ const char *pszRecord = ( LPCTSTR )p->m_szInRecord; do { // Copy the input record to the buffer we will pass the WriteFile(). int nIndex; for( nIndex = 0; nIndex < ( _IO_BUFFSIZE_ - 2 ) && *pszRecord; ++nIndex ) { szReadBuffer[ nIndex ] = *pszRecord; ++pszRecord; } szReadBuffer[ nIndex ] = 0; // If its the end of the record, tag on the newline character. if( !*pszRecord ) { szReadBuffer[ nIndex ] = _NEWLINE_; ++nIndex; szReadBuffer[ nIndex ] = 0; } #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "Writing: %s", szReadBuffer ); #endif // _PIPE_DIAG_MESSAGE_ if( !WriteFile( p->m_hInputWrite, szReadBuffer, ( DWORD )nIndex, &dwBytesWritten, NULL ) ) { if( GetLastError() == ERROR_NO_DATA ) { #ifdef _PIPE_DIAG_MESSAGE_ cons.Write( "The pipe is now closed!" ); #endif // _PIPE_DIAG_MESSAGE_ break; } else { DWORD dwRetCode = GetLastError(); CString szMessage;
(Use the "Code Block" formatting to properly format code in the future.) I'm assuming this is the server side. I see you are closing the pipe handle at the end of the function. Can I assume you're recreating the pipe somewhere else in the program?
The difficult we do right away... ...the impossible takes slightly longer.
-
(Use the "Code Block" formatting to properly format code in the future.) I'm assuming this is the server side. I see you are closing the pipe handle at the end of the function. Can I assume you're recreating the pipe somewhere else in the program?
The difficult we do right away... ...the impossible takes slightly longer.
As far as I understand - this is the server-side of the code - I cannot believe that it is so complicated to connect two process together .. with my application ..
-
As far as I understand - this is the server-side of the code - I cannot believe that it is so complicated to connect two process together .. with my application ..
Member 3852024 wrote:
I cannot believe that it is so complicated to connect two process together
That's why we developers get the big bucks! :laugh:
The difficult we do right away... ...the impossible takes slightly longer.
-
As far as I understand - this is the server-side of the code - I cannot believe that it is so complicated to connect two process together .. with my application ..
Maybe you just have a simple race condition. Maybe the process D is trying to connect before process A has a chance to re-open the pipe after process C disconnects.
The difficult we do right away... ...the impossible takes slightly longer.
-
Are you closing the pipe handle with
CloseHandle()
in process C before process D tries to connect?The difficult we do right away... ...the impossible takes slightly longer.
Thank you for looking into this for me. I am still at a loss as to why the process is not working. All the process' are synchronous - the mechanism I posted is one small part of a very big set of multi-threaded interlocked processes - however it is pretty much stand-alone - all it does is simulate the re-directed std handles of another process. For the first time in years - I am stuck! James.
-
Member 3852024 wrote:
I cannot believe that it is so complicated to connect two process together
That's why we developers get the big bucks! :laugh:
The difficult we do right away... ...the impossible takes slightly longer.
I wish I could get big bucks! I cannot get an IT job for love nor money!
-
Maybe you just have a simple race condition. Maybe the process D is trying to connect before process A has a chance to re-open the pipe after process C disconnects.
The difficult we do right away... ...the impossible takes slightly longer.
After some deliberation - I have decided to replace the whole mechanism with a shared file instead. It is a little ironic to say the least that I cannot get the pipe method to work for me - when my own application is called 'Pipelines'. Thank you for your help. Regards. James
-
Re-design of a process launched with re-directed STD streams. Process A creates two named pipes. One to write to the input of launched process B and one to read from process B. Standard stuff. Process B launches process C and D and E etc.. In that order and each one runs synchronously. So, only one sub-process is active at any one time. Process' C,D,E in turn connect to process A through the CreateFile() function - again standard stuff. Now, the first pass runs just fine - process C reads and writes records from/to A and then ends. Then process D starts - but there is nothing in the pipe. Process A puts stuff in the pipe - it is active all the time - (until process B terminates), then it deals with process E and so on .. I know that this a bit vague interms of detial - but I have tried every combination of CreateNamedPipe/ConnectNamedPipe/DisconnectNamedPipe on the server side and PeekNamePipe/ReadFile etc on the server side - with pipe busy and pipe closed returncodes. If anyone has an example or knows of where I can get some idea of how to design a server side mechanism that lets multiple synchronous clients connect in-turn then you would be my friend. I guess that I am missing something very simple - I hope.
I have read the entire thread so far and I think I see the problem here. The "Server" side of named pipes needs some magic in order to support multiple clients accessing it, even if those clients are "synchronized". A named pipe is still a "one shot deal", that is, you create it, wait for a connection, accept the connection, and then close the pipe when you are all done. That means that a single "client" can access the pipe. In order for multiple clients to work, you have to have multiple instances of the "named pipe", in other words, you have lots of pipes with the same name all ready for use. The easiest way to do this is demonstrated in the following pseudo-code (I cannot actually paste my working code as it belongs to my employer, as does my soul and first born
HANDLE P1 = create_a_named_pipe("Bob");
While (TRUE)
{
HANDLE P2 = create_a_named_pipe("Bob"); // A "pipe in waiting"wait_for_a_connection(P1);
// at this point, you can process the messages being passed on P1. You can either do it in
// this code or if you are communicating with "unsynchronized" clients, you might want to
// create a thread to work on P1. If you do that, make sure then make their own copy of
// P1 because we are about to clobber it.// once you are done processing the communication, close the P1 handle, here or in the thread
P1 = P2; // switch to the waiting pipe
}). Anyway, you need to maintain at least one "unattached" pipe with the proper name so that clients have something to "connect to" while you are busy working with the other client or cleaning up after you are done with it. Managing how one and only one application will have a pipe named "Bob" is an exercise for the student :)
-
I have read the entire thread so far and I think I see the problem here. The "Server" side of named pipes needs some magic in order to support multiple clients accessing it, even if those clients are "synchronized". A named pipe is still a "one shot deal", that is, you create it, wait for a connection, accept the connection, and then close the pipe when you are all done. That means that a single "client" can access the pipe. In order for multiple clients to work, you have to have multiple instances of the "named pipe", in other words, you have lots of pipes with the same name all ready for use. The easiest way to do this is demonstrated in the following pseudo-code (I cannot actually paste my working code as it belongs to my employer, as does my soul and first born
HANDLE P1 = create_a_named_pipe("Bob");
While (TRUE)
{
HANDLE P2 = create_a_named_pipe("Bob"); // A "pipe in waiting"wait_for_a_connection(P1);
// at this point, you can process the messages being passed on P1. You can either do it in
// this code or if you are communicating with "unsynchronized" clients, you might want to
// create a thread to work on P1. If you do that, make sure then make their own copy of
// P1 because we are about to clobber it.// once you are done processing the communication, close the P1 handle, here or in the thread
P1 = P2; // switch to the waiting pipe
}). Anyway, you need to maintain at least one "unattached" pipe with the proper name so that clients have something to "connect to" while you are busy working with the other client or cleaning up after you are done with it. Managing how one and only one application will have a pipe named "Bob" is an exercise for the student :)
Thank you very much for the update. I have already changed my code to use a shared file(s). Neverthless, after reading your comments - I can see exactly where my original design was wrong. I get it now. Thank you very much - this will be invaluable in other areas where I need to alter pipe processing connections.