/// <summary> /// Prova ad inviare il messaggio specificato al servizio configurato con la specifica istanza di questa classe. /// </summary> /// <param name="message">La query o la reply da inviare al servizio di un nodo vicino.</param> /// <param name="detection">L'eventuale istante di rilevamento del vicino.</param> /// <returns>true se non si sono vericati errori durante l'invio della query; in caso contrario, false.</returns> /// <remarks> /// Se si verificano errori durante la trasmissione del messaggio al servizio, questo metodo restituisce false /// e imposta il valore predefinito di un oggetto DateTime come istante di rilevazione, pertanto il valore non /// deve essere considerato. Invece, se il metodo restituisce true, vuol dire che non è avvenuto nessun errore /// durante la trasmissione del messaggio e quindi l'istante di rilevazione del servizio è corretto. /// </remarks> private bool TrySendMessage(MessageData message, out DateTime detection) { lock (m_SyncLock) { if (m_ProxyClosed || m_BindingConfig == null || m_RemoteUri == null) { detection = default(DateTime); return false; } try { if (m_InternalProxy == null) { ChannelFactory<IQueryReplyService> factory = new ChannelFactory<IQueryReplyService>(m_BindingConfig, new EndpointAddress(m_RemoteUri)); m_InternalProxy = factory.CreateChannel(); } if (message is QueryData) { WriteToLog("Dispatching query {0} to node {1}...", message.MsgId, m_TargetNodeId); m_InternalProxy.Query(m_NodeId, message as QueryData); } else if (message is ReplyData) { WriteToLog("Dispatching reply {0} to node {1}...", message.MsgId, m_TargetNodeId); m_InternalProxy.Reply(m_NodeId, message as ReplyData); } else { detection = default(DateTime); return false; } detection = DateTime.Now; return true; } catch { if (m_InternalProxy != null) { ICommunicationObject proxy = m_InternalProxy as ICommunicationObject; if (proxy.State == CommunicationState.Faulted) { proxy.Abort(); m_InternalProxy = null; } } detection = default(DateTime); return false; } } }
/// <summary> /// Crea una nuova istanza della classe NeighborClient usando i parametri specificati per la configurazione /// del proxy interno e per l'allocazione della coda dedicata ai messaggi in uscita. /// </summary> /// <param name="bindingConfig">Le impostazioni di configurazione del proxy interno.</param> /// <param name="remoteUri">L'uri del servizio remoto con cui il proxy deve comunicare.</param> /// <param name="nodeId">L'identificatore univoco del nodo rappresentato da questa istanza dell'applicazione.</param> /// <param name="nodeId">L'identificatore univoco del nodo di destinazione dei messaggi inviati da questa applicazione.</param> /// <param name="outputQueueSize">Il massimo numero di messaggi che possono essere inseriti nella coda.</param> /// <exception cref="ArgumentNullException">bindingConfig e/o remoteUri e/o nodeId e/o targetNodeId sono sull.</exception> /// <exception cref="ArgumentOutOfRangeException">outputQueueSize è minore o uguale a zero.</exception> /// <remarks> /// La configurazione del proxy interno è posticipata e viene pertanto eseguita non appena verrà richiesta /// la prima comunicazione col servizio remoto. /// </remarks> public NeighborClient(Binding bindingConfig, Uri remoteUri, string nodeId, string targetNodeId, int outputQueueSize) { if (bindingConfig == null) throw new ArgumentNullException("bindingConfig"); if (remoteUri == null) throw new ArgumentNullException("remoteUri"); if (nodeId == null) throw new ArgumentNullException("nodeId"); if (targetNodeId == null) throw new ArgumentNullException("targetNodeId"); if (targetNodeId == nodeId) throw new ArgumentException("Target node identifier must be different from current node identifier.", "targetNodeId"); if (outputQueueSize < 1) throw new ArgumentOutOfRangeException("outputQueueSize", "The size must be positive."); m_BindingConfig = bindingConfig; m_RemoteUri = remoteUri; m_NodeId = nodeId; m_TargetNodeId = targetNodeId; m_InternalProxy = null; m_ProxyClosed = false; m_OutputQueueSize = outputQueueSize; m_OutputQueue = new Queue<MessageData>(outputQueueSize); m_Shutdown = false; m_Dispatcher = new Thread(Send) { IsBackground = true }; }
/// <summary> /// Rilascia le risorse utilizzate per la comunicazione col servizio remoto di query/reply e richiede /// lo shutdown del thread dedicato all'invio dei messaggi. Questo metodo restituisce il controllo al /// chiamante dopo un tempo massimo pari al timeout specificato. /// </summary> /// <param name="millisecondsTimeout">Il tempo massimo di attesa per il termine di esecuzione del thread.</param> /// <exception cref="ArgumentOutOfRangeException"> /// Il valore di millisecondsTimeout è negativo e non è uguale a Timeout.Infinite in millisecondi. /// </exception> public void Dispose(int millisecondsTimeout) { lock (m_SyncLock) { if (m_InternalProxy != null) { ICommunicationObject proxy = m_InternalProxy as ICommunicationObject; try { proxy.Close(); } catch { if (proxy.State == CommunicationState.Faulted) { proxy.Abort(); } } finally { m_InternalProxy = null; m_ProxyClosed = true; } } if (!m_Shutdown) { m_Shutdown = true; Monitor.Pulse(m_SyncLock); } } m_Dispatcher.Join(millisecondsTimeout); }