/// <summary> /// Sends a single object to the provided endPoint. NOTE: Any possible reply will be ignored unless listening for incoming udp packets. /// </summary> /// <param name="sendingPacketType">The sending packet type</param> /// <param name="objectToSend">The object to send</param> /// <param name="ipEndPoint">The destination IPEndPoint. Supports multicast endpoints.</param> /// <param name="sendReceiveOptions">The sendReceiveOptions to use for this send</param> public static void SendObject(string sendingPacketType, object objectToSend, IPEndPoint ipEndPoint, SendReceiveOptions sendReceiveOptions) { UDPConnection connectionToUse; lock (udpRogueSenderCreationLocker) { if (NetworkComms.commsShutdown) { throw new CommunicationException("Attempting to send UDP packet but NetworkCommsDotNet is in the process of shutting down."); } else if (!udpRogueSenders.ContainsKey(ipEndPoint.AddressFamily) || udpRogueSenders[ipEndPoint.AddressFamily].ConnectionInfo.ConnectionState == ConnectionState.Shutdown) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace("Creating UDPRougeSender."); } IPAddress any; if (ipEndPoint.AddressFamily == AddressFamily.InterNetwork) { any = IPAddress.Any; } else if (ipEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { any = IPAddress.IPv6Any; } else { throw new CommunicationException("Attempting to send UDP packet over unsupported network address family: " + ipEndPoint.AddressFamily.ToString()); } udpRogueSenders[ipEndPoint.AddressFamily] = new UDPConnection(new ConnectionInfo(true, ConnectionType.UDP, new IPEndPoint(any, 0), new IPEndPoint(any, 0)), NetworkComms.DefaultSendReceiveOptions, UDPOptions.None, false); } //Get the rouge sender here connectionToUse = udpRogueSenders[ipEndPoint.AddressFamily]; } //Get connection defaults if no sendReceiveOptions were provided if (sendReceiveOptions == null) { sendReceiveOptions = connectionToUse.ConnectionDefaultSendReceiveOptions; } //If we are listening on what will be the outgoing adaptor we send with that client to ensure reply packets are collected //Determining this is annoyingly non-trivial //For now we will use the following method and look to improve upon it in future //Some very quick testing gave an average runtime of this method to be 0.12ms (averageover 1000 iterations) (perhaps not so bad after all) try { IPEndPoint localEndPoint = NetworkComms.BestLocalEndPoint(ipEndPoint); lock (udpClientListenerLocker) { IPEndPoint existingLocalEndPoint = ExistingLocalListenEndPoints(localEndPoint.Address); if (existingLocalEndPoint != null) { connectionToUse = udpConnectionListeners[existingLocalEndPoint]; } } } catch (Exception ex) { //if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Failed to determine preferred existing udpClientListener to " + ipEndPoint.Address + ":" + ipEndPoint.Port + ". Will just use the rogue udp sender instead."); NetworkComms.LogError(ex, "BestLocalEndPointError"); } using (Packet sendPacket = new Packet(sendingPacketType, objectToSend, sendReceiveOptions)) connectionToUse.SendPacketSpecific(sendPacket, ipEndPoint); }
/// <summary> /// Internal UDP creation method that performs the necessary tasks /// </summary> /// <param name="connectionInfo"></param> /// <param name="defaultSendReceiveOptions"></param> /// <param name="level"></param> /// <param name="listenForReturnPackets"></param> /// <param name="existingConnection"></param> /// <returns></returns> internal static UDPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, UDPOptions level, bool listenForReturnPackets, UDPConnection existingConnection) { connectionInfo.ConnectionType = ConnectionType.UDP; UDPConnection connection = null; lock (NetworkComms.globalDictAndDelegateLocker) { if (NetworkComms.ConnectionExists(connectionInfo.RemoteEndPoint, ConnectionType.UDP)) { connection = (UDPConnection)NetworkComms.GetExistingConnection(connectionInfo.RemoteEndPoint, ConnectionType.UDP); } else { //If we are listening on what will be the outgoing adaptor we send with that client to ensure if our connection info is handed off we are connectable by others if (existingConnection == null) { try { IPEndPoint localEndPoint = NetworkComms.BestLocalEndPoint(connectionInfo.RemoteEndPoint); lock (udpClientListenerLocker) { IPEndPoint existingLocalEndPoint = ExistingLocalListenEndPoints(localEndPoint.Address); if (existingLocalEndPoint != null) { existingConnection = udpConnectionListeners[existingLocalEndPoint]; //If we are using an existing listener there is no need to listen for packets listenForReturnPackets = false; } } } catch (Exception) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace("Failed to determine preferred existing udpClientListener to " + connectionInfo.RemoteEndPoint.Address + ":" + connectionInfo.RemoteEndPoint.Port.ToString() + ". Will create an isolated udp connection instead."); } } } //If an existing connection does not exist but the info we are using suggests it should we need to reset the info //so that it can be reused correctly. This case generally happens when using Comms in the format //UDPConnection.GetConnection(info).SendObject(packetType, objToSend); if (connectionInfo.ConnectionState == ConnectionState.Established || connectionInfo.ConnectionState == ConnectionState.Shutdown) { connectionInfo.ResetConnectionInfo(); } connection = new UDPConnection(connectionInfo, defaultSendReceiveOptions, level, listenForReturnPackets, existingConnection); } } if (!NetworkComms.commsShutdown) { TriggerConnectionKeepAliveThread(); } return(connection); }