Duplex named pipe hangs on a certain write

前端 未结 3 1270
被撕碎了的回忆
被撕碎了的回忆 2021-02-10 08:56

I have a C++ pipe server app and a C# pipe client app communicating via Windows named pipe (duplex, message mode, wait/blocking in separate read thread).

It all works fi

相关标签:
3条回答
  • 2021-02-10 09:30

    If you are using separate threads you will be unable to read from the pipe at the same time you write to it. For example, if you are doing a blocking read from the pipe then a subsequent blocking write (from a different thread) then the write call will wait/block until the read call has completed and in many cases if this is unexpected behavior your program will become deadlocked.

    I have not tested overlapped I/O, but it MAY be able to resolve this issue. However, if you are determined to use synchronous calls then the following models below may help you to solve the problem.

    Master/Slave

    You could implement a master/slave model in which the client or the server is the master and the other end only responds which is generally what you will find the MSDN examples to be.

    In some cases you may find this problematic in the event the slave periodically needs to send data to the master. You must either use an external signaling mechanism (outside of the pipe) or have the master periodically query/poll the slave or you can swap the roles where the client is the master and the server is the slave.

    Writer/Reader

    You could use a writer/reader model where you use two different pipes. However, you must associate those two pipes somehow if you have multiple clients since each pipe will have a different handle. You could do this by having the client send a unique identifier value on connection to each pipe which would then let the server associate the two pipes. This number could be the current system time or even a unique identifier that is global or local.

    Threads

    If you are determined to use the synchronous API you can use threads with the master/slave model if you do not want to be blocked while waiting for a message on the slave side. You will however want to lock the reader after it reads a message (or encounters the end of a series of message) then write the response (as the slave should) and finally unlock the reader. You can lock and unlock the reader using locking mechanisms that put the thread to sleep as these would be most efficient.

    Security Problem With TCP

    The loss going with TCP instead of named pipes is also the biggest possible problem. A TCP stream does not contain any security natively. So if security is a concern you will have to implement that and you have the possibility of creating a security hole since you would have to handle authentication yourself. The named pipe can provide security if you properly set the parameters. Also, to note again more clearly: security is no simple matter and generally you will want to use existing facilities that have been designed to provide it.

    0 讨论(0)
  • 2021-02-10 09:43

    It seems to me that what you are trying to do will rather not work as expected. Some time ago I was trying to do something that looked like your code and got similar results, the pipe just hanged and it was difficult to establish what had gone wrong.

    I would rather suggest to use client in very simple way:

    1. CreateFile
    2. Write request
    3. Read answer
    4. Close pipe.

    If you want to have two way communication with clients which are also able to receive unrequested data from server you should rather implement two servers. This was the workaround I used: here you can find sources.

    0 讨论(0)
  • 2021-02-10 09:45

    I think you may be running into problems with named pipes message mode. In this mode, each write to the kernel pipe handle constitutes a message. This doesn't necessarily correspond with what your application regards a Message to be, and a message may be bigger than your read buffer.

    This means that your pipe reading code needs two loops, the inner reading until the current [named pipe] message has been completely received, and the outer looping until your [application level] message has been received.

    Your C# client code does have a correct inner loop, reading again if IsMessageComplete is false:

    do
    {
        len += mPipeStream.Read(buffer, len, buffer.Length);
    } while (len>0 && !mPipeStream.IsMessageComplete);
    

    Your C++ server code doesn't have such a loop - the equivalent at the Win32 API level is testing for the return code ERROR_MORE_DATA.

    My guess is that somehow this is leading to the client waiting for the server to read on one pipe instance, whilst the server is waiting for the client to write on another pipe instance.

    0 讨论(0)
提交回复
热议问题