Exemple #1
0
        /// <summary>
        /// Subscribes (or re-subscribes) to a data publisher for a set of data points.
        /// </summary>
        /// <param name="remotelySynchronized">Boolean value that determines if subscription should be remotely synchronized - note that data publisher may not allow remote synchronization.</param>
        /// <param name="compactFormat">Boolean value that determines if the compact measurement format should be used. Set to <c>false</c> for full fidelity measurement serialization; otherwise set to <c>true</c> for bandwidth conservation.</param>
        /// <param name="connectionString">Connection string that defines required and optional parameters for the subscription.</param>
        /// <returns><c>true</c> if subscribe transmission was successful; otherwise <c>false</c>.</returns>
        public virtual bool Subscribe(bool remotelySynchronized, bool compactFormat, string connectionString)
        {
            bool success = false;

            if (!string.IsNullOrWhiteSpace(connectionString))
            {
                try
                {
                    // Parse connection string to see if it contains a data channel definition
                    Dictionary<string, string> settings = connectionString.ParseKeyValuePairs();
                    UdpClient dataChannel = null;
                    string setting;

                    // Track specified time inclusion for later deserialization
                    if (settings.TryGetValue("includeTime", out setting))
                        m_includeTime = setting.ParseBoolean();
                    else
                        m_includeTime = true;

                    settings.TryGetValue("dataChannel", out setting);

                    if (!string.IsNullOrWhiteSpace(setting))
                    {
                        dataChannel = new UdpClient(setting);

                        dataChannel.ReceiveBufferSize = ushort.MaxValue;
                        dataChannel.MaxConnectionAttempts = -1;
                        dataChannel.ConnectAsync();
                    }

                    // Assign data channel client reference and attach to needed events
                    DataChannel = dataChannel;

                    // Setup subscription packet
                    using (BlockAllocatedMemoryStream buffer = new BlockAllocatedMemoryStream())
                    {
                        DataPacketFlags flags = DataPacketFlags.NoFlags;
                        byte[] bytes;

                        if (remotelySynchronized)
                            flags |= DataPacketFlags.Synchronized;

                        if (compactFormat)
                            flags |= DataPacketFlags.Compact;

                        // Write data packet flags into buffer
                        buffer.WriteByte((byte)flags);

                        // Get encoded bytes of connection string
                        bytes = m_encoding.GetBytes(connectionString);

                        // Write encoded connection string length into buffer
                        buffer.Write(BigEndian.GetBytes(bytes.Length), 0, 4);

                        // Encode connection string into buffer
                        buffer.Write(bytes, 0, bytes.Length);

                        // Cache subscribed synchronization state
                        m_synchronizedSubscription = remotelySynchronized;

                        // Send subscribe server command with associated command buffer
                        success = SendServerCommand(ServerCommand.Subscribe, buffer.ToArray());
                    }
                }
                catch (Exception ex)
                {
                    OnProcessException(new InvalidOperationException("Exception occurred while trying to make publisher subscription: " + ex.Message, ex));
                }
            }
            else
                OnProcessException(new InvalidOperationException("Cannot make publisher subscription without a connection string."));

            // Reset decompressor on successful resubscription
            if (success && (object)m_decompressionBlock != null)
                m_decompressionBlock.Reset();

            return success;
        }
            /// <summary>
            /// Releases a reference to this client's shared client,
            /// and disposes of the shared client if nobody is using it.
            /// </summary>
            private void ReturnSharedClient()
            {
                EndPoint localEndPoint;

                lock (s_sharedClients)
                {
                    if ((object)m_udpClient == null)
                        return;

                    // Detach from event handlers
                    m_udpClient.ConnectionAttempt -= SharedClient_ConnectionAttempt;
                    m_udpClient.ConnectionEstablished -= SharedClient_ConnectionEstablished;
                    m_udpClient.ConnectionException -= SharedClient_ConnectionException;
                    m_udpClient.ConnectionTerminated -= SharedClient_ConnectionTerminated;
                    m_udpClient.ReceiveDataException -= SharedClient_ReceiveDataException;
                    m_udpClient.ReceiveDataFrom -= SharedClient_ReceiveDataFrom;
                    m_udpClient.SendDataException -= SharedClient_SendDataException;

                    // Decrement reference count
                    localEndPoint = GetLocalEndPoint();
                    s_sharedReferenceCount[localEndPoint]--;

                    if (s_sharedReferenceCount[localEndPoint] == 0)
                    {
                        // No more references to UDP client
                        // exist so dispose of it
                        m_udpClient.Disconnect();
                        m_udpClient.Dispose();
                        s_sharedClients.Remove(localEndPoint);
                        s_sharedReferenceCount.Remove(localEndPoint);
                    }

                    // Release reference to UDP client
                    m_udpClient = null;
                }
            }
            /// <summary>
            /// Terminates the client as quickly as possible and
            /// removes it from the collection of shared clients.
            /// </summary>
            private void TerminateSharedClient()
            {
                EndPoint localEndPoint;
                UdpClient sharedClient;

                lock (s_sharedClients)
                {
                    localEndPoint = GetLocalEndPoint();

                    if (s_sharedClients.TryGetValue(localEndPoint, out sharedClient))
                    {
                        // If the wrapped client and the shared client are the same,
                        // no one has terminated the shared client yet
                        if (m_udpClient == sharedClient)
                        {
                            // Disconnect and dispose of the old client
                            m_udpClient.Disconnect();
                            m_udpClient.Dispose();

                            // Remove the old client from the
                            // collection of shared clients
                            localEndPoint = GetLocalEndPoint();
                            s_sharedClients.Remove(localEndPoint);
                            s_sharedReferenceCount.Remove(localEndPoint);
                        }
                    }

                    m_udpClient = null;
                }
            }
            /// <summary>
            /// Gets a reference to the shared client listening
            /// on this client's local end point.
            /// </summary>
            /// <returns>A reference to a shared client.</returns>
            private void GetSharedClient()
            {
                const string ConfigurationMismatchError = "Configuration mismatch detected between parsers using shared UDP client: {0}";

                bool sharing;
                EndPoint localEndPoint;
                UdpClient sharedClient;

                lock (s_sharedClients)
                {
                    localEndPoint = GetLocalEndPoint();
                    sharing = s_sharedClients.TryGetValue(localEndPoint, out sharedClient);

                    if (sharing)
                    {
                        // Validate settings to ensure that they match
                        if (sharedClient.ReceiveBufferSize != m_receiveBufferSize)
                            throw new InvalidOperationException(string.Format(ConfigurationMismatchError, "Receive buffer size"));

                        if (sharedClient.MaxConnectionAttempts != m_maxConnectionAttempts)
                            throw new InvalidOperationException(string.Format(ConfigurationMismatchError, "Max connection attempts"));
                    }
                    else
                    {
                        // Create new client and add it to the shared list
                        sharedClient = new UdpClient();
                        s_sharedClients.Add(localEndPoint, sharedClient);
                        s_sharedReferenceCount.Add(localEndPoint, 0);
                    }

                    // Set the UDP client member variable ASAP to guarantee
                    // that it is set before callbacks can be triggered
                    m_udpClient = sharedClient;

                    // Attach to event handlers
                    sharedClient.ConnectionAttempt += SharedClient_ConnectionAttempt;
                    sharedClient.ConnectionEstablished += SharedClient_ConnectionEstablished;
                    sharedClient.ConnectionException += SharedClient_ConnectionException;
                    sharedClient.ConnectionTerminated += SharedClient_ConnectionTerminated;
                    sharedClient.ReceiveDataException += SharedClient_ReceiveDataException;
                    sharedClient.ReceiveDataFrom += SharedClient_ReceiveDataFrom;
                    sharedClient.SendDataException += SharedClient_SendDataException;
                    sharedClient.UnhandledUserException += SharedClient_UnhandledUserException;

                    // Make sure to set packet info flag if needed since
                    // other SharedUdpClientReferences may not need it
                    if (m_receivePacketInfo)
                        sharedClient.ReceivePacketInfo = true;

                    if (!sharing)
                    {
                        // Initialize settings and connect
                        sharedClient.ConnectionString = m_connectionString;
                        sharedClient.ReceiveBufferSize = m_receiveBufferSize;
                        sharedClient.MaxConnectionAttempts = m_maxConnectionAttempts;
                        sharedClient.ConnectAsync();
                    }

                    // Increment reference count
                    s_sharedReferenceCount[localEndPoint]++;
                }

                if (sharing && sharedClient.CurrentState == ClientState.Connected)
                    OnConnectionEstablished();
            }