/// <summary> /// Initializes a new instance of the <see cref="SmartSocketServer"/> class. /// Construct a new SmartSocketServer. /// </summary> /// <param name="name">The name the client will check in UDP broadcasts to make sure it is connecting to the right server.</param> /// <param name="resolver">A way of providing custom Message types for serialization.</param> /// <param name="ipAddress">An optional ipAddress so you can decide which network interface to use.</param> /// <param name="udpGroupAddress">An optional UDP group address.</param> /// <param name="udpGroupPort">An optional UDP group port.</param> private SmartSocketServer(string name, SmartSocketTypeResolver resolver, string ipAddress = "127.0.0.1:0", string udpGroupAddress = "226.10.10.2", int udpGroupPort = 37992) { this.ServiceName = name; this.Resolver = resolver; if (ipAddress.Contains(':')) { string[] parts = ipAddress.Split(':'); if (parts.Length == 2 && int.TryParse(parts[1], out int port)) { this.IpAddress = new IPEndPoint(IPAddress.Parse(parts[0]), port); } else { throw new ArgumentException("ipAddress is not a valid format"); } } else { this.IpAddress = new IPEndPoint(IPAddress.Parse(ipAddress), 0); } if (!string.IsNullOrEmpty(udpGroupAddress)) { this.GroupAddress = IPAddress.Parse(udpGroupAddress); this.GroupPort = udpGroupPort; } }
/// <summary> /// Start a new server that listens for connections from anyone. /// </summary> /// <param name="name">The unique name of the server.</param> /// <param name="resolver">For resolving custom message types received from the client.</param> /// <param name="ipAddress">Determines which local network interface to use.</param> /// <param name="udpGroupAddress">Optional request to setup UDP listener, pass null if you don't want that.</param> /// <param name="udpGroupPort">Optional port required if you provide udpGroupAddress.</param> /// <returns>Returns the new server object.</returns> public static SmartSocketServer StartServer(string name, SmartSocketTypeResolver resolver, string ipAddress, string udpGroupAddress = "226.10.10.2", int udpGroupPort = 37992) { if (string.IsNullOrEmpty(ipAddress)) { ipAddress = "127.0.0.1:0"; } SmartSocketServer server = new SmartSocketServer(name, resolver, ipAddress, udpGroupAddress, udpGroupPort); server.StartListening(); return(server); }
internal SmartSocketClient(SmartSocketServer server, Socket client, SmartSocketTypeResolver resolver) { this.Client = client; this.Stream = new NetworkStream(client); this.Server = server; this.Resolver = resolver; client.NoDelay = true; DataContractSerializerSettings settings = new DataContractSerializerSettings(); settings.DataContractResolver = this.Resolver; settings.PreserveObjectReferences = true; this.Serializer = new DataContractSerializer(typeof(MessageWrapper), settings); }
/// <summary> /// Find a SmartSocketServer on the local network using UDP broadcast. This will block /// waiting for a server to respond or until you cancel using the CancellationToken. /// </summary> /// <returns>The connected client or null if task is cancelled.</returns> public static async Task <SmartSocketClient> FindServerAsync(string serviceName, string clientName, SmartSocketTypeResolver resolver, CancellationToken token, string udpGroupAddress = "226.10.10.2", int udpGroupPort = 37992) { return(await Task.Run(async() => { string localHost = FindLocalHostName(); if (localHost is null) { return null; } while (!token.IsCancellationRequested) { try { var groupAddr = IPAddress.Parse(udpGroupAddress); IPEndPoint remoteEP = new IPEndPoint(groupAddr, udpGroupPort); UdpClient udpClient = new UdpClient(0); MemoryStream ms = new MemoryStream(); BinaryWriter writer = new BinaryWriter(ms); writer.Write(serviceName.Length); writer.Write(serviceName); byte[] bytes = ms.ToArray(); udpClient.Send(bytes, bytes.Length, remoteEP); CancellationTokenSource receiveTaskSource = new CancellationTokenSource(); Task <UdpReceiveResult> receiveTask = udpClient.ReceiveAsync(); if (receiveTask.Wait(5000, receiveTaskSource.Token)) { UdpReceiveResult result = receiveTask.Result; IPEndPoint serverEP = result.RemoteEndPoint; byte[] buffer = result.Buffer; BinaryReader reader = new BinaryReader(new MemoryStream(buffer)); int len = reader.ReadInt32(); string addr = reader.ReadString(); string[] parts = addr.Split(':'); if (parts.Length is 2) { var a = IPAddress.Parse(parts[0]); SmartSocketClient client = await ConnectAsync(new IPEndPoint(a, int.Parse(parts[1])), clientName, resolver); if (client != null) { client.ServerName = serviceName; client.Name = localHost; return client; } } } else { receiveTaskSource.Cancel(); } } catch (Exception ex) { Debug.WriteLine("Something went wrong with Udp connection: " + ex.Message); } } return null; })); }
internal static async Task <SmartSocketClient> ConnectAsync(IPEndPoint serverEP, string clientName, SmartSocketTypeResolver resolver) { Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); bool connected = false; CancellationTokenSource src = new CancellationTokenSource(); try { Task task = Task.Run(() => { try { client.Connect(serverEP); connected = true; } catch (Exception e) { Debug.WriteLine("Connect exception: " + e.Message); } }, src.Token); // give it 30 seconds to connect... if (!task.Wait(60000)) { src.Cancel(); } } catch (TaskCanceledException) { // move on... } if (connected) { var result = new SmartSocketClient(null, client, resolver) { Name = clientName, ServerName = GetHostName(serverEP.Address) }; SocketMessage response = await result.SendReceiveAsync(new SocketMessage(ConnectedMessageId, clientName)); return(result); } return(null); }