private static int Main(string[] args) { if (args.Length != 3) { Console.WriteLine("usage: remote_thr <connect-to> <message-size> <message-count>"); return 1; } string connectTo = args[0]; int messageSize = int.Parse(args[1]); int messageCount = int.Parse(args[2]); using (var context = NetMQContext.Create()) using (var push = context.CreatePushSocket()) { push.Connect(connectTo); for (int i = 0; i != messageCount; i++) { var message = new Msg(); message.InitPool(messageSize); push.Send(ref message, SendReceiveOptions.None); message.Close(); } } return 0; }
public void CopyPooled() { var pool = new MockBufferPool(); BufferPool.SetCustomBufferPool(pool); var msg = new Msg(); msg.InitPool(100); Assert.IsFalse(msg.IsShared); var copy = new Msg(); copy.Copy(ref msg); Assert.IsTrue(msg.IsShared); Assert.IsTrue(copy.IsShared); msg.Close(); Assert.AreEqual(0, pool.ReturnCallCount); Assert.IsFalse(msg.IsInitialised); Assert.IsNull(msg.Data); copy.Close(); Assert.AreEqual(1, pool.ReturnCallCount); Assert.IsFalse(copy.IsInitialised); Assert.IsNull(copy.Data); }
/// <summary> /// Set the specified option on this socket - which must be either a SubScribe or an Unsubscribe. /// </summary> /// <param name="option">which option to set</param> /// <param name="optionValue">the value to set the option to</param> /// <returns><c>true</c> if successful</returns> /// <exception cref="InvalidException">optionValue must be a String or a byte-array.</exception> protected override bool XSetSocketOption(ZmqSocketOption option, object optionValue) { // Only subscribe/unsubscribe options are supported if (option != ZmqSocketOption.Subscribe && option != ZmqSocketOption.Unsubscribe) return false; byte[] topic; if (optionValue is string) topic = Encoding.ASCII.GetBytes((string)optionValue); else if (optionValue is byte[]) topic = (byte[])optionValue; else throw new InvalidException($"In Sub.XSetSocketOption({option},{optionValue?.ToString() ?? "null"}), optionValue must be either a string or a byte-array."); // Create the subscription message. var msg = new Msg(); msg.InitPool(topic.Length + 1); msg.Put(option == ZmqSocketOption.Subscribe ? (byte)1 : (byte)0); msg.Put(topic, 1, topic.Length); try { // Pass it further on in the stack. var isMessageSent = base.XSend(ref msg); if (!isMessageSent) throw new Exception($"in Sub.XSetSocketOption({option}, {optionValue}), XSend returned false."); } finally { msg.Close(); } return true; }
/// <summary> /// Transmit a byte-array of data over this socket. /// </summary> /// <param name="socket">the IOutgoingSocket to transmit on</param> /// <param name="data">the byte-array of data to send</param> /// <param name="length">the number of bytes to send from <paramref name="data"/>.</param> /// <param name="options">options to control how the data is sent</param> public static void Send([NotNull] this IOutgoingSocket socket, [NotNull] byte[] data, int length, SendReceiveOptions options) { var msg = new Msg(); msg.InitPool(length); Buffer.BlockCopy(data, 0, msg.Data, 0, length); socket.Send(ref msg, options); msg.Close(); }
private static int Main(string[] args) { if (args.Length != 3) { Console.WriteLine("usage: local_thr <bind-to> <message-size> <message-count>"); return 1; } string bindTo = args[0]; int messageSize = int.Parse(args[1]); int messageCount = int.Parse(args[2]); using (var context = NetMQContext.Create()) using (var pullSocket = context.CreatePullSocket()) { pullSocket.Bind(bindTo); var message = new Msg(); message.InitEmpty(); pullSocket.Receive(ref message, SendReceiveOptions.None); var stopWatch = Stopwatch.StartNew(); for (int i = 0; i != messageCount - 1; i++) { pullSocket.Receive(ref message, SendReceiveOptions.None); if (message.Size != messageSize) { Console.WriteLine("message of incorrect size received. Received: " + message.Size + " Expected: " + messageSize); return -1; } } stopWatch.Stop(); var millisecondsElapsed = stopWatch.ElapsedMilliseconds; if (millisecondsElapsed == 0) millisecondsElapsed = 1; message.Close(); double messagesPerSecond = (double)messageCount/millisecondsElapsed*1000; double megabits = messagesPerSecond*messageSize*8/1000000; Console.WriteLine("message size: {0} [B]", messageSize); Console.WriteLine("message count: {0}", messageCount); Console.WriteLine("mean throughput: {0:0.000} [msg/s]", messagesPerSecond); Console.WriteLine("mean throughput: {0:0.000} [Mb/s]", megabits); pullSocket.Close(); } return 0; }
private static int Main(string[] args) { if (args.Length != 3) { Console.WriteLine("usage: remote_lat remote_lat <connect-to> <message-size> <roundtrip-count>"); return 1; } string connectTo = args[0]; int messageSize = int.Parse(args[1]); int roundtripCount = int.Parse(args[2]); using (var context = NetMQContext.Create()) using (var req = context.CreateRequestSocket()) { req.Connect(connectTo); var message = new Msg(); message.InitPool(messageSize); var stopWatch = Stopwatch.StartNew(); for (int i = 0; i != roundtripCount; i++) { req.Send(ref message, SendReceiveOptions.None); req.Receive(ref message, SendReceiveOptions.None); if (message.Size != messageSize) { Console.WriteLine("message of incorrect size received. Received: {0} Expected: {1}", message.Size, messageSize); return -1; } } stopWatch.Stop(); message.Close(); double elapsedMicroseconds = stopWatch.ElapsedTicks*1000000L/Stopwatch.Frequency; double latency = elapsedMicroseconds/(roundtripCount*2); Console.WriteLine("message size: {0} [B]", messageSize); Console.WriteLine("roundtrip count: {0}", roundtripCount); Console.WriteLine("average latency: {0:0.000} [µs]", latency); } return 0; }
public static byte[] Receive([NotNull] this IReceivingSocket socket, SendReceiveOptions options, out bool hasMore) { var msg = new Msg(); msg.InitEmpty(); socket.Receive(ref msg, options); var data = msg.CloneData(); hasMore = msg.HasMore; msg.Close(); return data; }
private static void ForwardTo(NetMQSocketEventArgs args, IOutgoingSocket toSocket) { var msg = new Msg(); msg.InitEmpty(); bool more; do { args.Socket.Receive(ref msg); more = msg.HasMore; toSocket.Send(ref msg, more); } while (more); msg.Close(); }
public static void Send([NotNull] this IOutgoingSocket socket, [NotNull] string message, [NotNull] Encoding encoding, SendReceiveOptions options) { var msg = new Msg(); // Count the number of bytes required to encode the string. // Note that non-ASCII strings may not have an equal number of characters // and bytes. The encoding must be queried for this answer. // With this number, request a buffer from the pool. msg.InitPool(encoding.GetByteCount(message)); // Encode the string into the buffer encoding.GetBytes(message, 0, message.Length, msg.Data, 0); socket.Send(ref msg, options); msg.Close(); }
public void Plug(IOThread ioThread, SessionBase session) { m_encoder.SetMsgSource(session); // get the first message from the session because we don't want to send identities var msg = new Msg(); msg.InitEmpty(); bool ok = session.PullMsg(ref msg); if (ok) { msg.Close(); } AddSocket(m_socket); m_state = State.Connecting; m_socket.Connect(m_pgmAddress.Address); }
protected override void XLeave(string @group) { if (group.Length > Msg.MaxGroupLength) { throw new InvalidException("Group maximum length is 255"); } if (!m_subscriptions.Remove(@group)) { throw new InvalidException("Socket didn't join group"); } Msg msg = new Msg(); msg.InitLeave(); msg.Group = group; m_distribution.SendToAll(ref msg); msg.Close(); }
public void InitDelimiter() { var msg = new Msg(); msg.InitDelimiter(); Assert.Equal(0, msg.Size); Assert.Equal(MsgType.Delimiter, msg.MsgType); Assert.Equal(MsgFlags.None, msg.Flags); Assert.Null(msg.UnsafeData); Assert.False(msg.HasMore); Assert.True(msg.IsDelimiter); Assert.False(msg.IsIdentity); Assert.True(msg.IsInitialised); msg.Close(); Assert.Equal(MsgType.Uninitialised, msg.MsgType); Assert.Null(msg.UnsafeData); }
public void InitEmpty() { var msg = new Msg(); msg.InitEmpty(); Assert.AreEqual(0, msg.Size); Assert.AreEqual(MsgType.Empty, msg.MsgType); Assert.AreEqual(MsgFlags.None, msg.Flags); Assert.IsNull(msg.Data); Assert.IsFalse(msg.HasMore); Assert.IsFalse(msg.IsDelimiter); Assert.IsFalse(msg.IsIdentity); Assert.IsTrue(msg.IsInitialised); msg.Close(); Assert.AreEqual(MsgType.Uninitialised, msg.MsgType); Assert.IsNull(msg.Data); }
public void InitGC() { var msg = new Msg(); var bytes = new byte[200]; msg.InitGC(bytes, 100); Assert.AreEqual(100, msg.Size); Assert.AreEqual(MsgType.GC, msg.MsgType); Assert.AreEqual(MsgFlags.None, msg.Flags); Assert.AreSame(bytes, msg.Data); Assert.IsFalse(msg.HasMore); Assert.IsFalse(msg.IsDelimiter); Assert.IsFalse(msg.IsIdentity); Assert.IsTrue(msg.IsInitialised); msg.Close(); Assert.AreEqual(MsgType.Uninitialised, msg.MsgType); Assert.IsNull(msg.Data); }
protected override void XJoin(string @group) { if (group.Length > Msg.MaxGroupLength) { throw new InvalidException("Group maximum length is 255"); } // User cannot join same group twice if (!m_subscriptions.Add(@group)) { throw new InvalidException("Group was already joined"); } Msg msg = new Msg(); msg.InitJoin(); msg.Group = group; m_distribution.SendToAll(ref msg); msg.Close(); }
/// <summary> /// Indicate the given pipe as being ready for reading by this socket. /// </summary> /// <param name="pipe">the <c>Pipe</c> that is now becoming available for reading</param> protected override void XReadActivated(Pipe pipe) { // There are some subscriptions waiting. Let's process them. var sub = new Msg(); while (pipe.Read(ref sub)) { // Apply the subscription to the trie. byte[] data = sub.Data; int size = sub.Size; if (size > 0 && (data[0] == 0 || data[0] == 1)) { if (m_manual) { m_lastPipe = pipe; m_pending.Enqueue(sub.CloneData()); } else { var unique = data[0] == 0 ? m_subscriptions.Remove(data, 1, size - 1, pipe) : m_subscriptions.Add(data, 1, size - 1, pipe); // If the subscription is not a duplicate, store it so that it can be // passed to used on next recv call. if (m_options.SocketType == ZmqSocketType.Xpub && (unique || m_verbose)) { m_pending.Enqueue(sub.CloneData()); } } } else // process message unrelated to sub/unsub { m_pending.Enqueue(sub.CloneData()); } sub.Close(); } }
static int Main(string[] args) { if (args.Length != 3) { Console.WriteLine("usage: local_lat <bind-to> <message-size> <roundtrip-count>"); return(1); } string bindTo = args[0]; int messageSize = int.Parse(args[1]); int roundtripCount = int.Parse(args[2]); var context = NetMQContext.Create(); var repSocket = context.CreateResponseSocket(); repSocket.Bind(bindTo); Msg message = new Msg(); message.InitEmpty(); for (int i = 0; i != roundtripCount; i++) { repSocket.Receive(ref message, SendReceiveOptions.None); if (message.Size != messageSize) { Console.WriteLine("message of incorrect size received. Received: " + message.Size + " Expected: " + messageSize); return(-1); } repSocket.Send(ref message, SendReceiveOptions.None); } message.Close(); repSocket.Close(); context.Terminate(); return(0); }
public override PullMsgResult Encode(ref Msg msg) { Span <byte> messageNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; m_encodeNoncePrefix.CopyTo(messageNonce); NetworkOrderBitsConverter.PutUInt64(m_nonce, messageNonce.Slice(16)); byte flags = 0; if (msg.HasMore) { flags |= 0x01; } if (msg.HasCommand) { flags |= 0x02; } Msg plaintext = new Msg(); plaintext.InitPool(msg.Size + 1); plaintext[0] = flags; msg.CopyTo(plaintext.Slice(1)); msg.Close(); msg.InitPool(16 + Curve25519XSalsa20Poly1305.TagLength + plaintext.Size); Assumes.NotNull(m_box); m_box.Encrypt(msg.Slice(16), plaintext, messageNonce); plaintext.Close(); MessageLiteral.CopyTo(msg); NetworkOrderBitsConverter.PutUInt64(m_nonce, msg.Slice(8)); m_nonce++; return(PullMsgResult.Ok); }
public static NetworkMessageBase ReceiveNetworkMsg(this NetMQSocket socket, TimeSpan timeout) { var inMsg = new Msg(); inMsg.InitEmpty(); try { socket.TryReceive(ref inMsg, timeout); } catch (Exception) { return(null); } var str = inMsg.Size > 0 ? Encoding.GetString(inMsg.Data, 0, inMsg.Size) : string.Empty; inMsg.Close(); return(NetworkMessageCoding.Decode(str)); }
/// <summary> /// Process the pipe-termination ack. /// </summary> protected override void ProcessPipeTermAck() { // Notify the user that all the references to the pipe should be dropped. Assumes.NotNull(m_sink); m_sink.Terminated(this); // In terminating and double_terminated states there's nothing to do. // Simply deallocate the pipe. In terminated state we have to ack the // peer before deallocating this side of the pipe. All the other states // are invalid. if (m_state == State.Terminated) { m_outboundPipe = null; Assumes.NotNull(m_peer); SendPipeTermAck(m_peer); } else { Debug.Assert(m_state == State.Terminating || m_state == State.DoubleTerminated); } Assumes.NotNull(m_inboundPipe); // We'll deallocate the inbound pipe, the peer will deallocate the outbound // pipe (which is an inbound pipe from its point of view). // First, delete all the unread messages in the pipe. We have to do it by // hand because msg_t doesn't have automatic destructor. Then deallocate // the ypipe itself. var msg = new Msg(); while (m_inboundPipe.TryRead(out msg)) { msg.Close(); } m_inboundPipe = null; }
public void CopyPooled() { var pool = new MockBufferPool(); BufferPool.SetCustomBufferPool(pool); var counterPool = new MockCounterPool(); AtomicCounterPool.SetCustomCounterPool(counterPool); var msg = new Msg(); msg.InitPool(100); Assert.False(msg.IsShared); var copy = new Msg(); copy.Copy(ref msg); Assert.True(msg.IsShared); Assert.True(copy.IsShared); msg.Close(); Assert.Equal(0, pool.ReturnCallCount); Assert.Equal(1, counterPool.ReturnCallCount); Assert.False(msg.IsInitialised); Assert.Null(msg.UnsafeData); copy.Close(); Assert.Equal(1, pool.ReturnCallCount); Assert.Equal(2, counterPool.ReturnCallCount); Assert.False(copy.IsInitialised); Assert.Null(copy.UnsafeData); }
private static int Main(string[] args) { if (args.Length != 3) { Console.WriteLine("usage: local_lat <bind-to> <message-size> <roundtrip-count>"); return 1; } string bindTo = args[0]; int messageSize = int.Parse(args[1]); int roundtripCount = int.Parse(args[2]); using (var context = NetMQContext.Create()) using (var rep = context.CreateResponseSocket()) { rep.Bind(bindTo); var message = new Msg(); message.InitEmpty(); for (int i = 0; i != roundtripCount; i++) { rep.Receive(ref message, SendReceiveOptions.None); if (message.Size != messageSize) { Console.WriteLine("message of incorrect size received. Received: " + message.Size + " Expected: " + messageSize); return -1; } rep.Send(ref message, SendReceiveOptions.None); } message.Close(); } return 0; }
public void InitPool() { var pool = new MockBufferPool(); BufferPool.SetCustomBufferPool(pool); var msg = new Msg(); Assert.AreEqual(0, pool.TakeCallCount); msg.InitPool(100); Assert.AreEqual(1, pool.TakeCallCount); Assert.AreEqual(100, pool.TakeSize[0]); Assert.AreEqual(100, msg.Size); Assert.AreEqual(MsgType.Pool, msg.MsgType); Assert.AreEqual(MsgFlags.None, msg.Flags); Assert.IsNotNull(msg.Data); Assert.AreEqual(100, msg.Data.Length); Assert.IsFalse(msg.HasMore); Assert.IsFalse(msg.IsDelimiter); Assert.IsFalse(msg.IsIdentity); Assert.IsTrue(msg.IsInitialised); Assert.AreEqual(0, pool.ReturnCallCount); var bytes = msg.Data; msg.Close(); Assert.AreEqual(1, pool.ReturnCallCount); Assert.AreSame(bytes, pool.ReturnBuffer[0]); Assert.AreEqual(MsgType.Uninitialised, msg.MsgType); Assert.IsNull(msg.Data); }
/// <summary> /// Remove any half processed messages. Flush unflushed messages. /// Call this function when engine disconnect to get rid of leftovers. /// </summary> private void CleanPipes() { if (m_pipe != null) { // Get rid of half-processed messages in the out pipe. Flush any // unflushed messages upstream. m_pipe.Rollback(); m_pipe.Flush(); // Remove any half-read message from the in pipe. while (m_incompleteIn) { var msg = new Msg(); msg.InitEmpty(); if (!PullMsg(ref msg)) { Debug.Assert(!m_incompleteIn); break; } msg.Close(); } } }
static XSub() { s_sendSubscription = (data, size, arg) => { var pipe = (Pipe)arg; // Create the subscription message. var msg = new Msg(); msg.InitPool(size + 1); msg.Put(1); msg.Put(data, 1, size); // Send it to the pipe. bool sent = pipe.Write(ref msg); // If we reached the SNDHWM, and thus cannot send the subscription, drop // the subscription message instead. This matches the behaviour of // zmq_setsockopt(ZMQ_SUBSCRIBE, ...), which also drops subscriptions // when the SNDHWM is reached. if (!sent) { msg.Close(); } }; }
public static bool SendNetworkMsg(this NetMQSocket socket, NetworkMessageBase message, uint timeoutMilliSeconds = GlobalConstants.StandardSendingTimeout) { var encodedMessage = NetworkMessageCoding.Encode(message); var outMsg = new Msg(); outMsg.InitPool(Encoding.GetByteCount(encodedMessage)); Encoding.GetBytes(encodedMessage, 0, encodedMessage.Length, outMsg.Data, 0); bool sendSuccessful; try { sendSuccessful = socket.TrySend(ref outMsg, TimeSpan.FromMilliseconds(timeoutMilliSeconds), false); } catch (Exception) { sendSuccessful = false; } outMsg.Close(); return(sendSuccessful); }
protected override void XReadActivated(Pipe pipe) { // There are some subscriptions waiting. Let's process them. Msg msg = new Msg(); while (pipe.Read(ref msg)) { // Apply the subscription to the trie if (msg.IsJoin || msg.IsLeave) { if (msg.IsJoin) { if (!m_subscriptions.TryGetValue(msg.Group, out var pipes)) { pipes = new HashSet <Pipe>(); m_subscriptions.Add(msg.Group, pipes); } pipes.Add(pipe); } else { if (m_subscriptions.TryGetValue(msg.Group, out var pipes)) { pipes.Remove(pipe); if (!pipes.Any()) { m_subscriptions.Remove(msg.Group); } } } } msg.Close(); } }
/// <summary> /// This method is called to assign the specified pipe as a replacement for the outbound pipe that was being used. /// </summary> /// <param name="pipe">the pipe to use for writing</param> /// <remarks> /// A "Hiccup" occurs when an outbound pipe experiences something like a transient disconnect or for whatever other reason /// is no longer available for writing to. /// </remarks> protected override void ProcessHiccup(object pipe) { // Destroy old out-pipe. Note that the read end of the pipe was already // migrated to this thread. Debug.Assert(m_outboundPipe != null); m_outboundPipe.Flush(); var msg = new Msg(); while (m_outboundPipe.TryRead(out msg)) { msg.Close(); } // Plug in the new out-pipe. Debug.Assert(pipe != null); m_outboundPipe = (YPipe <Msg>)pipe; m_outActive = true; // If appropriate, notify the user about the hiccup. if (m_state == State.Active) { m_sink.Hiccuped(this); } }
/// <summary> /// 将所有消息帧原封不动的发送至另外一端 /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="control"></param> private static void ProxyBetween(IReceivingSocket from, IOutgoingSocket to, IOutgoingSocket control) { Msg msg = default(Msg); msg.InitEmpty(); Msg msg2 = default(Msg); msg2.InitEmpty(); bool hasMore; do { from.Receive(ref msg); hasMore = msg.HasMore; if (control != null) { msg2.Copy(ref msg); control.Send(ref msg2, hasMore); } to.Send(ref msg, hasMore); }while (hasMore); msg2.Close(); msg.Close(); }
private static int Main(string[] args) { if (args.Length != 3) { Console.WriteLine("usage: local_lat <bind-to> <message-size> <roundtrip-count>"); return(1); } string bindTo = args[0]; int messageSize = int.Parse(args[1]); int roundtripCount = int.Parse(args[2]); using (var rep = new ResponseSocket()) { rep.Bind(bindTo); var msg = new Msg(); msg.InitEmpty(); for (int i = 0; i != roundtripCount; i++) { rep.Receive(ref msg); if (msg.Size != messageSize) { Console.WriteLine("message of incorrect size received. Received: " + msg.Size + " Expected: " + messageSize); return(-1); } rep.Send(ref msg, more: false); } msg.Close(); } return(0); }
/// <summary> /// Write the given Msg to the pipe. /// </summary> /// <param name="msg">the Msg to push to the pipe</param> /// <returns>true if the Msg was successfully sent</returns> public virtual bool PushMsg(ref Msg msg) { // First message to receive is identity (if required). if (!m_identityReceived) { msg.SetFlags(MsgFlags.Identity); m_identityReceived = true; if (!m_options.RecvIdentity) { msg.Close(); msg.InitEmpty(); return(true); } } if (m_pipe != null && m_pipe.Write(ref msg)) { msg.InitEmpty(); return(true); } return(false); }
private bool IdentifyPeer( Pipe pipe) { byte[] identity; if (m_options.RawSocket) { // Always assign identity for raw-socket identity = new byte[5]; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, identity, 1, 4); } else { // Pick up handshake cases and also case where next identity is set var msg = new Msg(); msg.InitEmpty(); bool ok = pipe.Read(ref msg); if (!ok) return false; if (msg.Size == 0) { // Fall back on the auto-generation identity = new byte[5]; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, identity, 1, 4); msg.Close(); } else { identity = msg.CloneData(); // Ignore peers with duplicate ID. if (m_outpipes.ContainsKey(identity)) { msg.Close(); return false; } msg.Close(); } } pipe.Identity = identity; // Add the record into output pipes lookup table var outpipe = new Outpipe(pipe, true); m_outpipes.Add(identity, outpipe); return true; }
/// <summary> /// Receive a message. The <c>Recv</c> method calls this lower-level method to do the actual receiving. /// </summary> /// <param name="msg">the <c>Msg</c> to receive the message into</param> /// <returns><c>true</c> if the message was received successfully, <c>false</c> if there were no messages to receive</returns> protected override bool XRecv(ref Msg msg) { // If there is at least one if (m_pending.Count == 0) return false; msg.Close(); byte[] first = m_pending.Dequeue(); msg.InitPool(first.Length); msg.Put(first, 0, first.Length); return true; }
/// <summary> /// Set the specified option on this socket - which must be either a SubScribe or an Unsubscribe. /// </summary> /// <param name="option">which option to set</param> /// <param name="optionValue">the value to set the option to</param> /// <returns><c>true</c> if successful</returns> /// <exception cref="InvalidException">optionValue must be a String or a byte-array.</exception> /// <exception cref="AgainException">XSend must return true.</exception> protected override bool XSetSocketOption(ZmqSocketOption option, object optionValue) { // Only subscribe/unsubscribe options are supported if (option != ZmqSocketOption.Subscribe && option != ZmqSocketOption.Unsubscribe) return false; byte[] topic; if (optionValue is string) topic = Encoding.ASCII.GetBytes((string)optionValue); else if (optionValue is byte[]) topic = (byte[])optionValue; else throw new InvalidException(string.Format("In Sub.XSetSocketOption({0},{1}), optionValue must be either a string or a byte-array.", option, (optionValue == null ? "null" : optionValue.ToString()))); // Create the subscription message. var msg = new Msg(); msg.InitPool(topic.Length + 1); msg.Put(option == ZmqSocketOption.Subscribe ? (byte)1 : (byte)0); msg.Put(topic, 1, topic.Length); try { // Pass it further on in the stack. bool isMessageSent = base.XSend(ref msg); if (!isMessageSent) { string xMsg = string.Format("in Sub.XSetSocketOption({0}, {1}), XSend returned false.", option, optionValue); // TODO: should we change the exception that is thrown here as AgainException is obsolete? #pragma warning disable 618 throw new AgainException(innerException: null, message: xMsg); #pragma warning restore 618 } } finally { msg.Close(); } return true; }
private bool IdentifyPeer([NotNull] Pipe pipe) { byte[] identity; if (m_options.RawSocket) { // Always assign identity for raw-socket identity = new byte[5]; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, identity, 1, 4); } else { // Pick up handshake cases and also case where next identity is set var msg = new Msg(); msg.InitEmpty(); bool ok = pipe.Read(ref msg); if (!ok) { return(false); } if (msg.Size == 0) { // Fall back on the auto-generation identity = new byte[5]; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, identity, 1, 4); msg.Close(); } else { identity = msg.CloneData(); msg.Close(); Outpipe existPipe; if (m_outpipes.TryGetValue(identity, out existPipe)) { if (!m_handover) { // Ignore peers with duplicate ID. return(false); } else { // We will allow the new connection to take over this // identity. Temporarily assign a new identity to the // existing pipe so we can terminate it asynchronously. var newIdentity = new byte[5]; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, newIdentity, 1, 4); existPipe.Pipe.Identity = newIdentity; m_outpipes.Add(newIdentity, existPipe); // Remove the existing identity entry to allow the new // connection to take the identity. m_outpipes.Remove(identity); if (existPipe.Pipe == m_currentIn) { m_closingCurrentIn = true; } else { existPipe.Pipe.Terminate(true); } } } } } pipe.Identity = identity; // Add the record into output pipes lookup table var outpipe = new Outpipe(pipe, true); m_outpipes.Add(identity, outpipe); return(true); }
/// <summary> /// Send the Example to the socket. /// </summary> public void Send(IOutgoingSocket output) { if (output is RouterSocket) { output.SendMoreFrame(RoutingId); } int frameSize = 2 + 1; // Signature and message ID switch (Id) { case MessageId.Log: frameSize += Log.GetFrameSize(); break; case MessageId.Structures: frameSize += Structures.GetFrameSize(); break; case MessageId.Binary: frameSize += Binary.GetFrameSize(); break; case MessageId.Types: frameSize += Types.GetFrameSize(); break; } // Now serialize message into the buffer Msg msg = new Msg(); msg.InitPool(frameSize); try { m_offset = 0; m_buffer = msg.Data; // put signature PutNumber2(0xAAA0 | 0); // put message id PutNumber1((byte)Id); switch (Id) { case MessageId.Log: Log.Write(this); break; case MessageId.Structures: Structures.Write(this); break; case MessageId.Binary: Binary.Write(this); break; case MessageId.Types: Types.Write(this); break; } // Send the data frame output.Send(ref msg, false); } finally { m_buffer = null; msg.Close(); } }
/// <summary> /// Transmit the given message. The <c>Send</c> method calls this to do the actual sending. /// </summary> /// <param name="msg">the message to transmit</param> /// <returns><c>true</c> if the message was sent successfully</returns> /// <exception cref="HostUnreachableException">The receiving host must be identifiable.</exception> protected override bool XSend(ref Msg msg) { // If this is the first part of the message it's the ID of the // peer to send the message to. if (m_sendingState == State.RoutingId) { Debug.Assert(m_currentOut == null); // If we have malformed message (prefix with no subsequent message) // then just silently ignore it. if (msg.HasMore) { // Find the pipe associated with the routingId stored in the prefix. var routingId = msg.UnsafeToArray(); if (m_outpipes.TryGetValue(routingId, out Outpipe op)) { m_currentOut = op.Pipe; if (!m_currentOut.CheckWrite()) { op.Active = false; m_currentOut = null; if (!op.Pipe.Active) { throw new HostUnreachableException("In Peer.XSend"); } return(false); } } else { throw new HostUnreachableException("In Peer.XSend"); } m_sendingState = State.Data; } // Detach the message from the data buffer. msg.Close(); msg.InitEmpty(); return(true); } m_sendingState = State.RoutingId; // Peer sockets do not allow multipart data (ZMQ_SNDMORE) if (msg.HasMore) { throw new InvalidException(); } // Push the message into the pipe. If there's no out pipe, just drop it. if (m_currentOut != null) { bool ok = m_currentOut.Write(ref msg); if (ok) { m_currentOut.Flush(); } m_currentOut = null; } else { msg.Close(); } // Detach the message from the data buffer. msg.InitEmpty(); return(true); }
/// <summary> /// Process the pipe-termination ack. /// </summary> protected override void ProcessPipeTermAck() { // Notify the user that all the references to the pipe should be dropped. Debug.Assert(m_sink != null); m_sink.Terminated(this); // In terminating and double_terminated states there's nothing to do. // Simply deallocate the pipe. In terminated state we have to ack the // peer before deallocating this side of the pipe. All the other states // are invalid. if (m_state == State.Terminated) { m_outboundPipe = null; SendPipeTermAck(m_peer); } else Debug.Assert(m_state == State.Terminating || m_state == State.DoubleTerminated); // We'll deallocate the inbound pipe, the peer will deallocate the outbound // pipe (which is an inbound pipe from its point of view). // First, delete all the unread messages in the pipe. We have to do it by // hand because msg_t doesn't have automatic destructor. Then deallocate // the ypipe itself. var msg = new Msg(); while (m_inboundPipe.TryRead(out msg)) { msg.Close(); } m_inboundPipe = null; }
/// <summary> /// This method is called to assign the specified pipe as a replacement for the outbound pipe that was being used. /// </summary> /// <param name="pipe">the pipe to use for writing</param> /// <remarks> /// A "Hiccup" occurs when an outbound pipe experiences something like a transient disconnect or for whatever other reason /// is no longer available for writing to. /// </remarks> protected override void ProcessHiccup(object pipe) { // Destroy old out-pipe. Note that the read end of the pipe was already // migrated to this thread. Debug.Assert(m_outboundPipe != null); m_outboundPipe.Flush(); var msg = new Msg(); while (m_outboundPipe.TryRead(out msg)) { msg.Close(); } // Plug in the new out-pipe. Debug.Assert(pipe != null); m_outboundPipe = (YPipe<Msg>)pipe; m_outActive = true; // If appropriate, notify the user about the hiccup. if (m_state == State.Active) m_sink.Hiccuped(this); }
/// <summary> /// Remove unfinished parts of the outbound message from the pipe. /// </summary> public void Rollback() { // Remove incomplete message from the outbound pipe. if (m_outboundPipe != null) { var msg = new Msg(); while (m_outboundPipe.Unwrite(ref msg)) { Debug.Assert(msg.HasMore); msg.Close(); } } }
static XSub() { s_sendSubscription = (data, size, arg) => { var pipe = (Pipe)arg; // Create the subscription message. var msg = new Msg(); msg.InitPool(size + 1); msg.Put(1); msg.Put(data, 1, size); // Send it to the pipe. bool sent = pipe.Write(ref msg); // If we reached the SNDHWM, and thus cannot send the subscription, drop // the subscription message instead. This matches the behaviour of // zmq_setsockopt(ZMQ_SUBSCRIBE, ...), which also drops subscriptions // when the SNDHWM is reached. if (!sent) msg.Close(); }; }
/// <summary> /// Indicate the given pipe as being ready for reading by this socket. /// </summary> /// <param name="pipe">the <c>Pipe</c> that is now becoming available for reading</param> protected override void XReadActivated(Pipe pipe) { // There are some subscriptions waiting. Let's process them. var sub = new Msg(); var isBroadcast = false; while (pipe.Read(ref sub)) { // Apply the subscription to the trie. int size = sub.Size; if (size > 0 && (sub[0] == 0 || sub[0] == 1) && !isBroadcast) { if (m_manual) { m_pendingMessages.Enqueue(new KeyValuePair<Msg,Pipe>(sub, pipe)); } else { var unique = sub[0] == 0 ? m_subscriptions.Remove(sub.Data, sub.Offset + 1, size - 1, pipe) : m_subscriptions.Add(sub.Data, sub.Offset + 1, size - 1, pipe); // If the subscription is not a duplicate, store it so that it can be // passed to used on next recv call. if (m_options.SocketType == ZmqSocketType.Xpub && (unique || m_verbose)) { m_pendingMessages.Enqueue(new KeyValuePair<Msg, Pipe>(sub, null)); } else { sub.Close(); } } } else if (m_broadcastEnabled && size > 0 && sub[0] == 2) { m_pendingMessages.Enqueue(new KeyValuePair<Msg, Pipe>(sub, pipe)); isBroadcast = true; } else // process message unrelated to sub/unsub { // pipe is null here, no special treatment m_pendingMessages.Enqueue(new KeyValuePair<Msg, Pipe>(sub, null)); } } }
/// <summary> /// Receive a message. The <c>Recv</c> method calls this lower-level method to do the actual receiving. /// </summary> /// <param name="msg">the <c>Msg</c> to receive the message into</param> /// <returns><c>true</c> if the message was received successfully, <c>false</c> if there were no messages to receive</returns> protected override bool XRecv(ref Msg msg) { // If there is at least one if (m_pendingMessages.Count == 0) return false; msg.Close(); var msgPipe = m_pendingMessages.Dequeue(); msg = msgPipe.Key; // must check if m_lastPipe == null to avoid dequeue at the second frame of a broadcast message if (msgPipe.Value != null && m_lastPipe == null) { if (m_broadcastEnabled && msg[0] == 2) { m_lastPipeIsBroadcast = true; m_lastPipe = msgPipe.Value; } if (m_manual && (msg[0] == 0 || msg[0] == 1)) { m_lastPipeIsBroadcast = false; m_lastPipe = msgPipe.Value; } } return true; }
/// <summary> /// Transmit the given message. The <c>Send</c> method calls this to do the actual sending. /// </summary> /// <param name="msg">the message to transmit</param> /// <returns><c>true</c> if the message was sent successfully</returns> protected override bool XSend(ref Msg msg) { byte[] data = msg.Data; int size = msg.Size; if (size > 0 && data[0] == 1) { // Process the subscription. if (m_subscriptions.Add(data, 1, size - 1)) { m_distribution.SendToAll(ref msg); return true; } } else if (size > 0 && data[0] == 0) { if (m_subscriptions.Remove(data, 1, size - 1)) { m_distribution.SendToAll(ref msg); return true; } } else { // upstream message unrelated to sub/unsub m_distribution.SendToAll(ref msg); return true; } msg.Close(); msg.InitEmpty(); return true; }
/// <summary> /// Receive a Example from the socket. /// </summary> public void Receive(IReceivingSocket input) { bool more; if (input is RouterSocket) { Msg routingIdMsg = new Msg(); routingIdMsg.InitEmpty(); try { input.Receive(ref routingIdMsg); if (!routingIdMsg.HasMore) { throw new MessageException("No routing id"); } if (m_routingId == null || m_routingId.Length == routingIdMsg.Size) { m_routingId = new byte[routingIdMsg.Size]; } Buffer.BlockCopy(routingIdMsg.Data, 0, m_routingId, 0, m_routingId.Length); } finally { routingIdMsg.Close(); } } else { RoutingId = null; } Msg msg = new Msg(); msg.InitEmpty(); try { input.Receive(ref msg); m_offset = 0; m_buffer = msg.Data; more = msg.HasMore; UInt16 signature = GetNumber2(); if (signature != (0xAAA0 | 0)) { throw new MessageException("Invalid signature"); } // Get message id and parse per message type Id = (MessageId)GetNumber1(); switch (Id) { case MessageId.Log: Log.Read(this); break; case MessageId.Structures: Structures.Read(this); break; case MessageId.Binary: Binary.Read(this); break; case MessageId.Types: Types.Read(this); break; default: throw new MessageException("Bad message id"); } } finally { m_buffer = null; msg.Close(); } }
/// <summary> /// Put the message to all active pipes. /// </summary> private void Distribute(ref Msg msg) { // If there are no matching pipes available, simply drop the message. if (m_matching == 0) { msg.Close(); msg.InitEmpty(); return; } if (msg.MsgType != MsgType.Pool) { for (int i = 0; i < m_matching; ++i) { if (!Write(m_pipes[i], ref msg)) { --i; // Retry last write because index will have been swapped } } msg.Close(); msg.InitEmpty(); return; } // Add matching-1 references to the message. We already hold one reference, // that's why -1. msg.AddReferences(m_matching - 1); // Push copy of the message to each matching pipe. int failed = 0; for (int i = 0; i < m_matching; ++i) { if (!Write(m_pipes[i], ref msg)) { ++failed; --i; // Retry last write because index will have been swapped } } if (failed != 0) msg.RemoveReferences(failed); // Detach the original message from the data buffer. Note that we don't // close the message. That's because we've already used all the references. msg.InitEmpty(); }
public bool Send(ref Msg msg) { // Drop the message if required. If we are at the end of the message // switch back to non-dropping mode. if (m_dropping) { m_more = msg.HasMore; m_dropping = m_more; msg.Close(); msg.InitEmpty(); return true; } while (m_active > 0) { if (m_pipes[m_current].Write(ref msg)) break; Debug.Assert(!m_more); m_active--; if (m_current < m_active) m_pipes.Swap(m_current, m_active); else m_current = 0; } // If there are no pipes we cannot send the message. if (m_active == 0) { return false; } // If it's part of the message we can flush it downstream and // continue round-robinning (load balance). m_more = msg.HasMore; if (!m_more) { m_pipes[m_current].Flush(); if (m_active > 1) m_current = (m_current + 1) % m_active; } // Detach the message from the data buffer. msg.InitEmpty(); return true; }
public bool RecvPipe(Pipe[] pipe, ref Msg msg) { // Deallocate old content of the message. msg.Close(); // Round-robin over the pipes to get the next message. while (m_active > 0) { // Try to fetch new message. If we've already read part of the message // subsequent part should be immediately available. bool fetched = m_pipes[m_current].Read(ref msg); // Note that when message is not fetched, current pipe is deactivated // and replaced by another active pipe. Thus we don't have to increase // the 'current' pointer. if (fetched) { if (pipe != null) pipe[0] = m_pipes[m_current]; m_more = msg.HasMore; if (!m_more) m_current = (m_current + 1) % m_active; return true; } // Check the atomicity of the message. // If we've already received the first part of the message // we should get the remaining parts without blocking. Debug.Assert(!m_more); m_active--; m_pipes.Swap(m_current, m_active); if (m_current == m_active) m_current = 0; } // No message is available. Initialise the output parameter // to be a 0-byte message. msg.InitEmpty(); return false; }
/// <summary> /// Receive a message. The <c>Recv</c> method calls this lower-level method to do the actual receiving. /// </summary> /// <param name="msg">the <c>Msg</c> to receive the message into</param> /// <returns><c>true</c> if the message was received successfully, <c>false</c> if there were no messages to receive</returns> /// <exception cref="FiniteStateMachineException">Req.XRecv expecting send, not receive.</exception> protected override bool XRecv(ref Msg msg) { bool isMessageAvailable; // If request wasn't send, we can't wait for reply. if (!m_receivingReply) throw new FiniteStateMachineException("Req.XRecv - cannot receive another reply"); // First part of the reply should be the original request ID. if (m_messageBegins) { isMessageAvailable = base.XRecv(ref msg); if (!isMessageAvailable) return false; if (!msg.HasMore || msg.Size != 0) { while (true) { isMessageAvailable = base.XRecv(ref msg); Debug.Assert(isMessageAvailable); if (!msg.HasMore) break; } msg.Close(); msg.InitEmpty(); return false; } m_messageBegins = false; } isMessageAvailable = base.XRecv(ref msg); if (!isMessageAvailable) return false; // If the reply is fully received, flip the FSM into request-sending state. if (!msg.HasMore) { m_receivingReply = false; m_messageBegins = true; } return true; }
private static void ProxyBetween(NetMQSocket from, NetMQSocket to, [CanBeNull] NetMQSocket control) { var msg = new Msg(); msg.InitEmpty(); var copy = new Msg(); copy.InitEmpty(); while (true) { from.Receive(ref msg, SendReceiveOptions.None); bool more = from.Options.ReceiveMore; if (control != null) { copy.Copy(ref msg); control.Send(ref copy, more ? SendReceiveOptions.SendMore : SendReceiveOptions.None); } to.Send(ref msg, more ? SendReceiveOptions.SendMore : SendReceiveOptions.None); if (!more) { break; } } copy.Close(); msg.Close(); }
protected override bool XSend(ref Msg msg, SendReceiveOptions flags) { // If this is the first part of the message it's the ID of the // peer to send the message to. if (!m_moreOut) { Debug.Assert(m_currentOut == null); // If we have malformed message (prefix with no subsequent message) // then just silently ignore it. // TODO: The connections should be killed instead. if (msg.HasMore) { m_moreOut = true; // Find the pipe associated with the identity stored in the prefix. // If there's no such pipe just silently ignore the message, unless // mandatory is set. byte[] identity = msg.Data; if (msg.Size != msg.Data.Length) { identity = new byte[msg.Size]; Buffer.BlockCopy(msg.Data, 0, identity, 0, msg.Size); } Outpipe op; if (m_outpipes.TryGetValue(identity, out op)) { m_currentOut = op.Pipe; if (!m_currentOut.CheckWrite()) { op.Active = false; m_currentOut = null; if (m_mandatory) { m_moreOut = false; return(false); } } } else if (m_mandatory) { m_moreOut = false; throw new HostUnreachableException("In Router.XSend"); } } // Detach the message from the data buffer. msg.Close(); msg.InitEmpty(); return(true); } if (m_options.RawSocket) { msg.ResetFlags(MsgFlags.More); } // Check whether this is the last part of the message. m_moreOut = msg.HasMore; // Push the message into the pipe. If there's no out pipe, just drop it. if (m_currentOut != null) { // Close the remote connection if user has asked to do so // by sending zero length message. // Pending messages in the pipe will be dropped (on receiving term-ack) if (m_rawSocket && msg.Size == 0) { m_currentOut.Terminate(false); msg.Close(); msg.InitEmpty(); m_currentOut = null; return(true); } bool ok = m_currentOut.Write(ref msg); if (!ok) { m_currentOut = null; } else if (!m_moreOut) { m_currentOut.Flush(); m_currentOut = null; } } else { msg.Close(); } // Detach the message from the data buffer. msg.InitEmpty(); return(true); }
/// <summary> /// Transmit the given message. The <c>Send</c> method calls this to do the actual sending. /// </summary> /// <param name="msg">the message to transmit</param> /// <returns><c>true</c> if the message was sent successfully</returns> /// <exception cref="HostUnreachableException">The receiving host must be identifiable.</exception> protected override bool XSend(ref Msg msg) { // If this is the first part of the message it's the ID of the // peer to send the message to. if (!m_moreOut) { Debug.Assert(m_currentOut == null); // If we have malformed message (prefix with no subsequent message) // then just silently ignore it. // TODO: The connections should be killed instead. if (msg.HasMore) { m_moreOut = true; // Find the pipe associated with the identity stored in the prefix. // If there's no such pipe just silently ignore the message, unless // mandatory is set. var identity = msg.Size == msg.Data.Length ? msg.Data : msg.CloneData(); Outpipe op; if (m_outpipes.TryGetValue(identity, out op)) { m_currentOut = op.Pipe; if (!m_currentOut.CheckWrite()) { op.Active = false; m_currentOut = null; if (m_mandatory) { m_moreOut = false; return false; } } } else if (m_mandatory) { m_moreOut = false; throw new HostUnreachableException("In Router.XSend"); } } // Detach the message from the data buffer. msg.Close(); msg.InitEmpty(); return true; } if (m_options.RawSocket) { msg.ResetFlags(MsgFlags.More); } // Check whether this is the last part of the message. m_moreOut = msg.HasMore; // Push the message into the pipe. If there's no out pipe, just drop it. if (m_currentOut != null) { // Close the remote connection if user has asked to do so // by sending zero length message. // Pending messages in the pipe will be dropped (on receiving term-ack) if (m_rawSocket && msg.Size == 0) { m_currentOut.Terminate(false); msg.Close(); msg.InitEmpty(); m_currentOut = null; return true; } bool ok = m_currentOut.Write(ref msg); if (!ok) m_currentOut = null; else if (!m_moreOut) { m_currentOut.Flush(); m_currentOut = null; } } else { msg.Close(); } // Detach the message from the data buffer. msg.InitEmpty(); return true; }
/// <summary> /// Transmit the given message. The <c>Send</c> method calls this to do the actual sending. /// </summary> /// <param name="msg">the message to transmit</param> /// <returns><c>true</c> if the message was sent successfully</returns> /// <exception cref="HostUnreachableException">In Stream.XSend</exception> protected override bool XSend(ref Msg msg) { // If this is the first part of the message it's the ID of the // peer to send the message to. if (!this.m_moreOut) { Debug.Assert(this.m_currentOut == null); // If we have malformed message (prefix with no subsequent message) // then just silently ignore it. // TODO: The connections should be killed instead. if (msg.HasMore) { // Find the pipe associated with the identity stored in the prefix. // If there's no such pipe just silently ignore the message, unless // mandatory is set. byte[] identity = msg.Size == msg.Data.Length ? msg.Data : msg.CloneData(); Outpipe op; if (this.m_outpipes.TryGetValue(identity, out op)) { this.m_currentOut = op.Pipe; if (!this.m_currentOut.CheckWrite()) { op.Active = false; this.m_currentOut = null; return(false); } } else { throw new HostUnreachableException("In Stream.XSend"); } } this.m_moreOut = true; msg.Close(); msg.InitEmpty(); return(true); } // Ignore the MORE flag msg.ResetFlags(MsgFlags.More); // This is the last part of the message. this.m_moreOut = false; // Push the message into the pipe. If there's no out pipe, just drop it. if (this.m_currentOut != null) { if (msg.Size == 0) { this.m_currentOut.Terminate(false); this.m_currentOut = null; return(true); } bool ok = this.m_currentOut.Write(ref msg); if (ok) { this.m_currentOut.Flush(); } this.m_currentOut = null; } // Detach the message from the data buffer. msg.InitEmpty(); return(true); }
/// <summary> /// Write the given Msg to the pipe. /// </summary> /// <param name="msg">the Msg to push to the pipe</param> /// <returns>true if the Msg was successfully sent</returns> public virtual bool PushMsg(ref Msg msg) { // First message to receive is identity (if required). if (!m_identityReceived) { msg.SetFlags(MsgFlags.Identity); m_identityReceived = true; if (!m_options.RecvIdentity) { msg.Close(); msg.InitEmpty(); return true; } } if (m_pipe != null && m_pipe.Write(ref msg)) { msg.InitEmpty(); return true; } return false; }
public override void Destroy() { base.Destroy(); m_prefetchedId.Close(); m_prefetchedMsg.Close(); }
public override void Destroy() { base.Destroy(); m_message.Close(); }
private bool IdentifyPeer([NotNull] Pipe pipe) { byte[] identity; if (m_options.RawSocket) { // Always assign identity for raw-socket identity = new byte[5]; identity[0] = 0; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, identity, 1, 4); } else { // Pick up handshake cases and also case where next identity is set var msg = new Msg(); msg.InitEmpty(); bool ok = pipe.Read(ref msg); if (!ok) { return(false); } if (msg.Size == 0) { // Fall back on the auto-generation identity = new byte[5]; identity[0] = 0; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, identity, 1, 4); msg.Close(); } else { identity = new byte[msg.Size]; Buffer.BlockCopy(msg.Data, 0, identity, 0, msg.Size); // Ignore peers with duplicate ID. if (m_outpipes.ContainsKey(identity)) { msg.Close(); return(false); } msg.Close(); } } pipe.Identity = identity; // Add the record into output pipes lookup table var outpipe = new Outpipe(pipe, true); m_outpipes.Add(identity, outpipe); return(true); }
protected override void Produce(PushSocket socket, int messageSize) { var msg = new Msg(); for (int i = 0; i < MsgCount; i++) { msg.InitGC(new byte[messageSize], messageSize); msg.Data[messageSize / 2] = 0x42; socket.Send(ref msg, more: false); msg.Close(); } }