/// <summary> /// Sends the specified packet to this node. /// </summary> /// <param name="packet">The packet to send.</param> public void SendData(INodePacket packet) { MemoryStream writeStream = new MemoryStream(); ITranslator writeTranslator = BinaryTranslator.GetWriteTranslator(writeStream); try { writeStream.WriteByte((byte)packet.Type); // Pad for the packet length writeStream.Write(BitConverter.GetBytes((int)0), 0, 4); packet.Translate(writeTranslator); // Now plug in the real packet length writeStream.Position = 1; writeStream.Write(BitConverter.GetBytes((int)writeStream.Length - 5), 0, 4); byte[] writeStreamBuffer = writeStream.GetBuffer(); for (int i = 0; i < writeStream.Length; i += MaxPacketWriteSize) { int lengthToWrite = Math.Min((int)writeStream.Length - i, MaxPacketWriteSize); if ((int)writeStream.Length - i <= MaxPacketWriteSize) { // We are done, write the last bit asynchronously. This is actually the general case for // most packets in the build, and the asynchronous behavior here is desirable. #if FEATURE_APM _serverToClientStream.BeginWrite(writeStreamBuffer, i, lengthToWrite, PacketWriteComplete, null); #else _serverToClientStream.WriteAsync(writeStreamBuffer, i, lengthToWrite); #endif return; } else { // If this packet is longer that we can write in one go, then we need to break it up. We can't // return out of this function and let the rest of the system continue because another operation // might want to send data immediately afterward, and that could result in overlapping writes // to the pipe on different threads. #if FEATURE_APM IAsyncResult result = _serverToClientStream.BeginWrite(writeStream.GetBuffer(), i, lengthToWrite, null, null); _serverToClientStream.EndWrite(result); #else _serverToClientStream.Write(writeStreamBuffer, i, lengthToWrite); #endif } } } catch (IOException e) { // Do nothing here because any exception will be caught by the async read handler CommunicationsUtilities.Trace(_nodeId, "EXCEPTION in SendData: {0}", e); } catch (ObjectDisposedException) // This happens if a child dies unexpectedly { // Do nothing here because any exception will be caught by the async read handler } }
/// <summary> /// Actually writes and sends the packet. This can't be called in parallel /// because it reuses the _writeBufferMemoryStream, and this is why we use /// the _packetWriteDrainTask to serially chain invocations one after another. /// </summary> /// <param name="packet">The packet to send.</param> private void SendDataCore(INodePacket packet) { MemoryStream writeStream = _writeBufferMemoryStream; // clear the buffer but keep the underlying capacity to avoid reallocations writeStream.SetLength(0); ITranslator writeTranslator = BinaryTranslator.GetWriteTranslator(writeStream); try { writeStream.WriteByte((byte)packet.Type); // Pad for the packet length WriteInt32(writeStream, 0); packet.Translate(writeTranslator); int writeStreamLength = (int)writeStream.Position; // Now plug in the real packet length writeStream.Position = 1; WriteInt32(writeStream, writeStreamLength - 5); byte[] writeStreamBuffer = writeStream.GetBuffer(); for (int i = 0; i < writeStreamLength; i += MaxPacketWriteSize) { int lengthToWrite = Math.Min(writeStreamLength - i, MaxPacketWriteSize); _serverToClientStream.Write(writeStreamBuffer, i, lengthToWrite); } if (IsExitPacket(packet)) { _exitPacketState = ExitPacketState.ExitPacketSent; } } catch (IOException e) { // Do nothing here because any exception will be caught by the async read handler CommunicationsUtilities.Trace(_nodeId, "EXCEPTION in SendData: {0}", e); } catch (ObjectDisposedException) // This happens if a child dies unexpectedly { // Do nothing here because any exception will be caught by the async read handler } }
/// <summary> /// Sends the specified packet to this node. /// </summary> /// <param name="packet">The packet to send.</param> public void SendData(INodePacket packet) { MemoryStream writeStream = new MemoryStream(); INodePacketTranslator writeTranslator = NodePacketTranslator.GetWriteTranslator(writeStream); try { writeStream.WriteByte((byte)packet.Type); // Pad for the packet length writeStream.Write(BitConverter.GetBytes((int)0), 0, 4); packet.Translate(writeTranslator); // Now plug in the real packet length writeStream.Position = 1; writeStream.Write(BitConverter.GetBytes((int)writeStream.Length - 5), 0, 4); #if FALSE if (trace) // Avoid method call { CommunicationsUtilities.Trace(nodeId, "Sending Packet of type {0} with length {1}", packet.Type.ToString(), writeStream.Length - 5); } #endif for (int i = 0; i < writeStream.Length; i += MaxPacketWriteSize) { int lengthToWrite = Math.Min((int)writeStream.Length - i, MaxPacketWriteSize); if ((int)writeStream.Length - i <= MaxPacketWriteSize) { // We are done, write the last bit asynchronously. This is actually the general case for // most packets in the build, and the asynchronous behavior here is desirable. _nodePipe.BeginWrite(writeStream.GetBuffer(), i, lengthToWrite, PacketWriteComplete, null); return; } else { // If this packet is longer that we can write in one go, then we need to break it up. We can't // return out of this function and let the rest of the system continue because another operation // might want to send data immediately afterward, and that could result in overlapping writes // to the pipe on different threads. IAsyncResult result = _nodePipe.BeginWrite(writeStream.GetBuffer(), i, lengthToWrite, null, null); _nodePipe.EndWrite(result); } } } catch (IOException e) { // Do nothing here because any exception will be caught by the async read handler CommunicationsUtilities.Trace(_nodeId, "EXCEPTION in SendData: {0}", e); } catch (ObjectDisposedException) // This happens if a child dies unexpectedly { // Do nothing here because any exception will be caught by the async read handler } }