/// <summary> /// Sends the specified packet to this node asynchronously. /// The method enqueues a task to write the packet and returns /// immediately. This is because SendData() is on a hot path /// under the primary lock (BuildManager's _syncLock) /// and we want to minimize our time there. /// </summary> /// <param name="packet">The packet to send.</param> public void SendData(INodePacket packet) { if (IsExitPacket(packet)) { _exitPacketState = ExitPacketState.ExitPacketQueued; } _packetWriteQueue.Add(packet); DrainPacketQueue(); }
/// <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 } }