Exemplo n.º 1
0
        /// <summary>
        /// P/Invoke native APIs related to named pipe operations to create the named pipe.
        /// System.IO.Pipes in Unity is missing crucial types/methods for performing reliable and
        /// accurate transfers. Such as bytesSents/bytesReceived.
        /// </summary>
        public static void Run()
        {
            while (!KillServerRequested)
            {
                // ----------------------------------------------------------------------------------------------------------------
                // Create the named pipe.
                using (SafePipeHandle hNamedPipe = NativeMethod.CreateNamedPipe(
                           IPCServer.FullPipeName,          // The unique pipe name.
                           PipeOpenMode.PIPE_ACCESS_DUPLEX, // The pipe is duplex
                           PipeMode.PIPE_TYPE_MESSAGE |     // Message type pipe
                           PipeMode.PIPE_READMODE_MESSAGE | // Message-read mode
                           PipeMode.PIPE_WAIT,              // Blocking mode is on
                           2,                               // Max server instances
                           IPCServer.BufferSize,            // Output buffer size
                           IPCServer.BufferSize,            // Input buffer size
                           NMPWAIT_USE_DEFAULT_WAIT         // Time-out interval
                           ))
                {
                    try
                    {
                        if (hNamedPipe.IsInvalid)
                        {
                            throw new Win32Exception();
                        }

                        pipeHandle = hNamedPipe;
                        Console.WriteLine("[IPC Server Waiting for Connection] - \"{0}\"", IPCServer.FullPipeName);

                        // ----------------------------------------------------------------------------------------------------------------
                        // Wait for the connections. Runs on background thread.
                        if (!NativeMethod.ConnectNamedPipe(hNamedPipe, IntPtr.Zero))
                        {
                            if (Marshal.GetLastWin32Error() != ERROR_PIPE_CONNECTED)
                            {
                                throw new Win32Exception();
                            }
                        }
                        Console.WriteLine("[IPC Server Status] - Client Connected");

                        // ----------------------------------------------------------------------------------------------------------------
                        // Received a request from client.
                        string message;
                        bool   finishRead = false;
                        do
                        {
                            byte[] bRequest = new byte[IPCServer.BufferSize];
                            int    cbRequest = bRequest.Length, cbRead;

                            finishRead = NativeMethod.ReadFile(
                                hNamedPipe,             // Handle of the pipe
                                bRequest,               // Buffer to receive data
                                cbRequest,              // Size of buffer in bytes
                                out cbRead,             // Number of bytes read
                                IntPtr.Zero             // Not overlapped
                                );

                            if (!finishRead && Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
                            {
                                throw new Win32Exception();
                            }

                            // UTF8-encode the received byte array and trim all the '\0' characters at the end.
                            message = Encoding.UTF8.GetString(bRequest).Replace("\0", "");
                            Console.WriteLine("[IPC Server Received {0} bytes] Message: {1}\r\n", cbRead, message);
                        }while (!finishRead); // Repeat loop if ERROR_MORE_DATA

                        // If message is not KILL_SERVER, then process client request
                        if (message != "KILL_SERVER")
                        {
                            //Get our message header and data
                            string[] msgArray = message.Split(new string[] { "|:|" }, StringSplitOptions.None);
                            string   header   = msgArray[0];
                            string   data     = msgArray[1];

                            // Process Client Requests Here based off request header
                            Console.WriteLine("    Message Header: " + header);
                            Order order = JsonConvert.DeserializeObject <Order>(data);
                            Console.WriteLine("    Message Data: {0} ordered {1} {2}, delivery address: {3}\r\n", order.CustomerName, order.Quantity, order.ProductName, order.Address);
                        }

                        // ----------------------------------------------------------------------------------------------------------------
                        // Send a message received response to client.
                        string rmessage = IPCServer.ResponseMessage;
                        byte[] bResponse = Encoding.UTF8.GetBytes(rmessage);
                        int    cbResponse = bResponse.Length, cbWritten;

                        if (!NativeMethod.WriteFile(
                                hNamedPipe,             // Handle of the pipe
                                bResponse,              // Message to be written
                                cbResponse,             // Number of bytes to write
                                out cbWritten,          // Number of bytes written
                                IntPtr.Zero             // Not overlapped
                                ))
                        {
                            throw new Win32Exception();
                        }

                        Console.WriteLine("[IPC Server Sent {0} bytes] Message: {1}", cbWritten, rmessage.Replace("\0", ""));

                        if (message == "KILL_SERVER")
                        {
                            KillServerRequested = true;
                        }

                        // ----------------------------------------------------------------------------------------------------------------
                        // Flush the pipe to allow the client to read the pipe's contents before disconnecting. Then disconnect the client's connection.
                        NativeMethod.FlushFileBuffers(hNamedPipe);
                        NativeMethod.DisconnectNamedPipe(hNamedPipe);
                    }
                    catch (Exception ex)
                    {
                        if (ex.Message != "Thread was being aborted")
                        {
                            Console.WriteLine("[IPC Server ERROR] - {0}", ex.Message);
                        }

                        hNamedPipe.Close();
                        hNamedPipe.Dispose();
                        NativeMethod.DisconnectNamedPipe(hNamedPipe);
                    }
                    finally
                    {
                        if (hNamedPipe != null)
                        {
                            hNamedPipe.Close();
                            hNamedPipe.Dispose();
                            NativeMethod.DisconnectNamedPipe(hNamedPipe);
                        }
                    }
                }
            }

            if (KillServerRequested)
            {
                _ipcServer.StopServer();
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// P/Invoke the native APIs related to named pipe operations to create
        /// the named pipe.
        /// </summary>
        public static void Run()
        {
            SafePipeHandle hNamedPipe = null;

            try
            {
                // Prepare the security attributes (the securityAttributes
                // parameter in CreateNamedPipe) for the pipe. This is optional.
                // If securityAttributes of CreateNamedPipe is null, the named
                // pipe gets a default security descriptor and the handle cannot
                // be inherited. The ACLs in the default security descriptor of a
                // pipe grant full control to the LocalSystem account, (elevated)
                // administrators, and the creator owner. They also give only
                // read access to members of the Everyone group and the anonymous
                // account. However, if you want to customize the security
                // permission of the pipe, (e.g. to allow Authenticated Users to
                // read from and write to the pipe), you need to create a
                // SECURITY_ATTRIBUTES object.
                SECURITY_ATTRIBUTES sa = null;
                sa = CreateNativePipeSecurity();

                // Create the named pipe.
                hNamedPipe = NativeMethod.CreateNamedPipe(
                    Program.FullPipeName,               // The unique pipe name.
                    PipeOpenMode.PIPE_ACCESS_DUPLEX,    // The pipe is duplex
                    PipeMode.PIPE_TYPE_MESSAGE |        // Message type pipe
                    PipeMode.PIPE_READMODE_MESSAGE |    // Message-read mode
                    PipeMode.PIPE_WAIT,                 // Blocking mode is on
                    PIPE_UNLIMITED_INSTANCES,           // Max server instances
                    Program.BufferSize,                 // Output buffer size
                    Program.BufferSize,                 // Input buffer size
                    NMPWAIT_USE_DEFAULT_WAIT,           // Time-out interval
                    sa                                  // Pipe security attributes
                    );

                if (hNamedPipe.IsInvalid)
                {
                    throw new Win32Exception();
                }

                Console.WriteLine("The named pipe ({0}) is created.",
                                  Program.FullPipeName);

                // Wait for the client to connect.
                Console.WriteLine("Waiting for the client's connection...");
                if (!NativeMethod.ConnectNamedPipe(hNamedPipe, IntPtr.Zero))
                {
                    if (Marshal.GetLastWin32Error() != ERROR_PIPE_CONNECTED)
                    {
                        throw new Win32Exception();
                    }
                }
                Console.WriteLine("Client is connected.");

                //
                // Receive a request from client.
                //

                string message;
                bool   finishRead = false;
                do
                {
                    byte[] bRequest = new byte[Program.BufferSize];
                    int    cbRequest = bRequest.Length, cbRead;

                    finishRead = NativeMethod.ReadFile(
                        hNamedPipe,             // Handle of the pipe
                        bRequest,               // Buffer to receive data
                        cbRequest,              // Size of buffer in bytes
                        out cbRead,             // Number of bytes read
                        IntPtr.Zero             // Not overlapped
                        );

                    if (!finishRead &&
                        Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
                    {
                        throw new Win32Exception();
                    }

                    // Unicode-encode the received byte array and trim all the
                    // '\0' characters at the end.
                    message = Encoding.Unicode.GetString(bRequest).TrimEnd('\0');
                    Console.WriteLine("Receive {0} bytes from client: \"{1}\"",
                                      cbRead, message);
                }while (!finishRead);  // Repeat loop if ERROR_MORE_DATA

                //
                // Send a response from server to client.
                //

                message = Program.ResponseMessage;
                byte[] bResponse = Encoding.Unicode.GetBytes(message);
                int    cbResponse = bResponse.Length, cbWritten;

                if (!NativeMethod.WriteFile(
                        hNamedPipe,             // Handle of the pipe
                        bResponse,              // Message to be written
                        cbResponse,             // Number of bytes to write
                        out cbWritten,          // Number of bytes written
                        IntPtr.Zero             // Not overlapped
                        ))
                {
                    throw new Win32Exception();
                }

                Console.WriteLine("Send {0} bytes to client: \"{1}\"",
                                  cbWritten, message.TrimEnd('\0'));

                // Flush the pipe to allow the client to read the pipe's contents
                // before disconnecting. Then disconnect the client's connection.
                NativeMethod.FlushFileBuffers(hNamedPipe);
                NativeMethod.DisconnectNamedPipe(hNamedPipe);
            }
            catch (Exception ex)
            {
                Console.WriteLine("The server throws the error: {0}", ex.Message);
            }
            finally
            {
                if (hNamedPipe != null)
                {
                    hNamedPipe.Close();
                    hNamedPipe = null;
                }
            }
        }