/// <summary> /// Überträgt ein Objekt in eine Kommunikationseinheit. /// </summary> /// <param name="pipe">Die Kommunikationseinheit.</param> /// <param name="serializer">Die Serialisierungsinstanz.</param> /// <param name="instance">Das betroffene Objekt.</param> internal static void SendToPipe( PipeStream pipe, XmlSerializer serializer, object instance ) { // Create helper using (var temp = new MemoryStream()) { // Create writer configuration var settings = new XmlWriterSettings { CheckCharacters = false }; // Create using (var writer = XmlWriter.Create( temp, settings )) serializer.Serialize( writer, instance ); // Read data and create buffer for length var len = new byte[sizeof( long )]; var data = temp.ToArray(); // Lock briefly var lenLock = GCHandle.Alloc( len, GCHandleType.Pinned ); try { // Fill Marshal.WriteInt64( lenLock.AddrOfPinnedObject(), data.LongLength ); } finally { // Release lenLock.Free(); } // Send all pipe.Write( len, 0, len.Length ); // Write in blocks for (int n = 0; n < data.Length; ) { // Block size int block = Math.Min( BlockSize, data.Length - n ); // Send chunck pipe.Write( data, n, block ); pipe.Flush(); // Advance n += block; } // Flush pipe.Flush(); pipe.WaitForPipeDrain(); } }
//MAIN private NKRemotingProxy(string ns, string id, int nativeSeqMax, NKScriptMessage message, NKScriptContext context, CancellationToken cancelToken) { this.context = context; this._localHandlers = null; this.ns = ns; this.cancelToken = cancelToken; var exe = System.Reflection.Assembly.GetEntryAssembly().Location; var path = System.IO.Path.GetDirectoryName(exe); ProcessStartInfo startInfo = Process.GetCurrentProcess().StartInfo; startInfo.FileName = exe; startInfo.WorkingDirectory = path; startInfo.UseShellExecute = false; var syncPipeOut = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable); var syncPipeIn = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable); var pipeOutHandle = syncPipeOut.GetClientHandleAsString(); var pipeInHandle = syncPipeIn.GetClientHandleAsString(); this.syncPipeOut = syncPipeOut; this.syncPipeIn = syncPipeIn; startInfo.Arguments = "NKR=" + buildInitMessage(pipeOutHandle, pipeInHandle); this.id = id; process = Process.Start(startInfo); NKEventEmitter.global.emit<string>("NKS.ProcessAdded", id, false); process.EnableRaisingEvents = true; process.Exited += Process_Exited; var pipeName = Convert.ToBase64String(getUniqueKey()); var asyncPipe = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough); this.asyncPipe = asyncPipe; NKScriptChannel.nativeFirstSequence -= 5; string nativeFirstSeq = NKScriptChannel.nativeFirstSequence.ToString(); var handshake = new NKRemotingMessage(); handshake.command = NKRemotingMessage.Command.NKRemotingHandshake; handshake.args = new string[] { pipeName, ns, id, nativeSeqMax.ToString() }; syncPipeOut.WriteByte(100); syncPipeOut.Flush(); syncPipeOut.WaitForPipeDrain(); syncPipeOut.DisposeLocalCopyOfClientHandle(); syncPipeIn.DisposeLocalCopyOfClientHandle(); writeObject(syncPipeOut, handshake); syncPipeOut.WaitForPipeDrain(); var handshakeReply = readObject(syncPipeIn); if (handshakeReply == null || handshakeReply.command != NKRemotingMessage.Command.NKRemotingHandshake) Environment.Exit(911); asyncPipe.WaitForConnection(); cancelToken.Register(requestClientTeardown); var nkready = readObject(asyncPipe); if (nkready == null || nkready.command != NKRemotingMessage.Command.NKRemotingReady) Environment.Exit(910); Task.Factory.StartNew((s)=> _processServerMessages(asyncPipe), null, cancelToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); NKEventEmitter.global.forward<NKEvent>(eventForwarderFromMain); }
protected void HandlePipeConnection(PipeStream pipeStream, IDictionary<string, object> initialMessage) { // You think we'd scope these with using() right? They are IDisposable // after all... but nope, the implementation of these is such that // disposing of them also disposes the underlying stream. Leaving us // with a double (or triple if we close the pipeServer stream ourselves) // close. Yay. Instead we abandoned these to the GC knowing that they // are only wrappers anyway and have/use little/no resources of their own. BinaryReader reader = new BinaryReader(pipeStream, Encoding.Unicode); BinaryWriter writer = new BinaryWriter(pipeStream, Encoding.Unicode); try { // If we should announce with a specific message, do so if (initialMessage != null) { WriteMessage(writer, initialMessage); } // So long as our Func<> returns true, we keep going. When it returns false, // it is done and its time to closeup and look for another client. while (StreamAction(reader, writer)) { } } catch(Exception e) { LibraryLogging.Error("Error while using pipe connection: {0}", e); } try { pipeStream.Flush(); pipeStream.WaitForPipeDrain(); pipeStream.Close(); } catch(Exception e) { LibraryLogging.Error("Error while flushing/closing pipe connection: {0}", e); } }
public static void Write(BinaryFormatter formatter, PipeStream stream, object data, bool isAsync, TimeoutHelper timeoutHelper) { if (stream == null) { throw new ArgumentNullException("stream"); } if (data == null) { throw new ArgumentNullException("data"); } MemoryStream ms = new MemoryStream(stream.OutBufferSize * 2); BinaryWriter bw = new BinaryWriter(ms); try { //DateTime t = DateTime.Now; SerializeData(bw, formatter, data); //Console.WriteLine("序列化用时:" + (DateTime.Now - t).TotalMilliseconds); //t = DateTime.Now; // 先以流的输出缓冲大小为限定,进行一次写入 // 一方面,由于通常情况下,流的输出缓冲大小应可以一次性输出大部分的消息体,因此,大部分消息体的输出不需要继续进行后面的遍历; // 另一方面,我们需要先把流的整个长度输出,这需要先输出消息体的一小部分,选择流中定义的输出缓冲大小是一个比较适中的选择; byte[] bytes = new byte[ms.Length > stream.OutBufferSize ? stream.OutBufferSize : ms.Length]; ms.Read(bytes, 0, bytes.Length); PipeStreamRWHelper.Write(stream, bytes, 0, bytes.Length, isAsync, timeoutHelper); stream.Flush(); int index = bytes.Length; // 当消息体较大时,对流的其余部分进行输出,这些输出以 maxBufferSize 为基准对消息体进行分块输出 // 这尽可能的减少了循环的次数,进而减少了异步调用(需要使用工作线程)的开销,最终尽可能的提升了性能 while (index < ms.Length) { bytes = new byte[ms.Length - index > maxBufferSize ? maxBufferSize : ms.Length - index]; ms.Read(bytes, 0, bytes.Length); PipeStreamRWHelper.Write(stream, bytes, 0, bytes.Length, isAsync, timeoutHelper); stream.Flush(); index += bytes.Length; } //Console.WriteLine("输出用时:" + (DateTime.Now - t).TotalMilliseconds); } finally { bw.Close(); } }