public void SimpleSend(IByteBuffer source, bool bindClient, IByteBufferAllocator allocator, AddressFamily addressFamily, byte[] expectedData, int count) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return; } SocketDatagramChannel serverChannel = null; IChannel clientChannel = null; var serverGroup = new MultithreadEventLoopGroup(1); var clientGroup = new MultithreadEventLoopGroup(1); try { var handler = new TestHandler(expectedData); var serverBootstrap = new Bootstrap(); serverBootstrap .Group(serverGroup) .ChannelFactory(() => new SocketDatagramChannel(addressFamily)) .Option(ChannelOption.Allocator, allocator) .Option(ChannelOption.SoBroadcast, true) .Option(ChannelOption.IpMulticastLoopDisabled, false) .Handler(new ActionChannelInitializer <IChannel>(channel => { channel.Pipeline.AddLast(nameof(SocketDatagramChannelUnicastTest), handler); })); IPAddress address = NetUtil.GetLoopbackAddress(addressFamily); this.Output.WriteLine($"Unicast server binding to:({addressFamily}){address}"); Task <IChannel> task = serverBootstrap.BindAsync(address, IPEndPoint.MinPort); Assert.True(task.Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds * 5)), $"Unicast server binding to:({addressFamily}){address} timed out!"); serverChannel = (SocketDatagramChannel)task.Result; var endPoint = (IPEndPoint)serverChannel.LocalAddress; var clientBootstrap = new Bootstrap(); clientBootstrap .Group(clientGroup) .ChannelFactory(() => new SocketDatagramChannel(addressFamily)) .Option(ChannelOption.Allocator, allocator) .Option(ChannelOption.SoBroadcast, true) .Option(ChannelOption.IpMulticastLoopDisabled, false) .Handler(new ActionChannelInitializer <IChannel>(channel => { channel.Pipeline.AddLast("Dummy", new NetUtil.DummyHandler()); })); var clientEndPoint = new IPEndPoint( addressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, IPEndPoint.MinPort); clientBootstrap .LocalAddress(clientEndPoint) .RemoteAddress(new IPEndPoint(address, endPoint.Port)); if (bindClient) { this.Output.WriteLine($"Unicast client binding to:({addressFamily}){address}"); task = clientBootstrap.BindAsync(clientEndPoint); Assert.True(task.Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds * 5)), $"Unicast client binding to:({clientEndPoint}) timed out!"); clientChannel = task.Result; } else { this.Output.WriteLine($"Register client binding to:({addressFamily}){address}"); task = (Task <IChannel>)clientBootstrap.RegisterAsync(); Assert.True(task.Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds)), "Unicast client register timed out!"); clientChannel = task.Result; } for (int i = 0; i < count; i++) { var packet = new DatagramPacket((IByteBuffer)source.Retain(), new IPEndPoint(address, endPoint.Port)); clientChannel.WriteAndFlushAsync(packet).Wait(); Assert.True(handler.WaitForResult()); var duplicatedPacket = (DatagramPacket)packet.Duplicate(); duplicatedPacket.Retain(); clientChannel.WriteAndFlushAsync(duplicatedPacket).Wait(); Assert.True(handler.WaitForResult()); } } finally { serverChannel?.CloseAsync().Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds)); clientChannel?.CloseAsync().Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds)); source.Release(); Task.WaitAll( serverGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(5)), clientGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(5))); } }
public void Multicast(AddressFamily addressFamily, IByteBufferAllocator allocator) { SocketDatagramChannel serverChannel = null; IChannel clientChannel = null; var serverGroup = new MultithreadEventLoopGroup(1); var clientGroup = new MultithreadEventLoopGroup(1); NetworkInterface loopback = NetUtil.LoopbackInterface(addressFamily); try { var multicastHandler = new MulticastTestHandler(); var serverBootstrap = new Bootstrap(); serverBootstrap .Group(serverGroup) .ChannelFactory(() => new SocketDatagramChannel(addressFamily)) .Option(ChannelOption.Allocator, allocator) .Option(ChannelOption.SoReuseaddr, true) .Option(ChannelOption.IpMulticastLoopDisabled, false) .Handler(new ActionChannelInitializer <IChannel>(channel => { channel.Pipeline.AddLast(nameof(SocketDatagramChannelMulticastTest), multicastHandler); })); IPAddress address = addressFamily == AddressFamily.InterNetwork ? IPAddress.Loopback : IPAddress.IPv6Loopback; this.Output.WriteLine($"Multicast server binding to:({addressFamily}){address}"); Task <IChannel> task = serverBootstrap.BindAsync(address, IPEndPoint.MinPort); Assert.True(task.Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds * 5)), $"Multicast server binding to:({addressFamily}){address} timed out!"); serverChannel = (SocketDatagramChannel)task.Result; var serverEndPoint = (IPEndPoint)serverChannel.LocalAddress; var clientBootstrap = new Bootstrap(); clientBootstrap .Group(clientGroup) .ChannelFactory(() => new SocketDatagramChannel(addressFamily)) .Option(ChannelOption.Allocator, allocator) .Option(ChannelOption.SoReuseaddr, true) .Option(ChannelOption.IpMulticastLoopDisabled, false) .Handler(new ActionChannelInitializer <IChannel>(channel => { channel.Pipeline.AddLast("Dummy", new NetUtil.DummyHandler()); })); this.Output.WriteLine($"Multicast client binding to:({addressFamily}){address}"); task = clientBootstrap.BindAsync(address, IPEndPoint.MinPort); Assert.True(task.Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds * 5)), $"Multicast client binding to:({addressFamily}){address} timed out!"); clientChannel = (SocketDatagramChannel)task.Result; IPAddress multicastAddress = addressFamily == AddressFamily.InterNetwork ? IPAddress.Parse("230.0.0.1") : IPAddress.Parse("ff12::1"); var groupAddress = new IPEndPoint(multicastAddress, serverEndPoint.Port); Task joinTask = serverChannel.JoinGroup(groupAddress, loopback); Assert.True(joinTask.Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds * 5)), $"Multicast server join group {groupAddress} timed out!"); clientChannel.WriteAndFlushAsync(new DatagramPacket(Unpooled.Buffer().WriteInt(1), groupAddress)).Wait(); Assert.True(multicastHandler.WaitForResult(), "Multicast server should have receivied the message."); Task leaveTask = serverChannel.LeaveGroup(groupAddress, loopback); Assert.True(leaveTask.Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds * 5)), $"Multicast server leave group {groupAddress} timed out!"); // sleep half a second to make sure we left the group Task.Delay(DefaultTimeOutInMilliseconds).Wait(); // we should not receive a message anymore as we left the group before clientChannel.WriteAndFlushAsync(new DatagramPacket(Unpooled.Buffer().WriteInt(1), groupAddress)).Wait(); Assert.False(multicastHandler.WaitForResult(), "Multicast server should not receive the message."); } finally { serverChannel?.CloseAsync().Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds)); clientChannel?.CloseAsync().Wait(TimeSpan.FromMilliseconds(DefaultTimeOutInMilliseconds)); Task.WaitAll( serverGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)), clientGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1))); } }
public IObservable <IPEndPoint[]> MakeObservable() { return(Observable.Create <IPEndPoint[]>(async(observer, cancellationToken) => { try { Bootstrap clientBootstrap = new Bootstrap(); MultithreadEventLoopGroup clientGroup = new MultithreadEventLoopGroup(1); try { clientBootstrap .Group(clientGroup) .ChannelFactory(() => new SocketDatagramChannel(_addressFamily)) .Option(ChannelOption.Allocator, PooledByteBufferAllocator.Default) .Option(ChannelOption.SoReuseaddr, true) .Option(ChannelOption.IpMulticastLoopDisabled, false) .Handler(new ActionChannelInitializer <IChannel>(channel => { channel.Pipeline.AddLast(new SimpleChannelInboundHandler(_endPoints)); })); SocketDatagramChannel clientChannel = (SocketDatagramChannel)await clientBootstrap .BindAsync(IPAddress.Any, IPEndPoint.MinPort) .ConfigureAwait(false); try { IPEndPoint multicastEndPoint = new IPEndPoint(_multicastAddress, _disconveryServerPort); byte[] groupBytes = Encoding.UTF8.GetBytes(_group); IByteBuffer message = PooledByteBufferAllocator.Default .Buffer() .WriteInt(groupBytes.Length) .WriteBytes(groupBytes); DatagramPacket dataGram = new DatagramPacket(message, multicastEndPoint); while (!cancellationToken.IsCancellationRequested) { _endPoints.Clear(); await clientChannel .WriteAndFlushAsync(dataGram.Copy()) .ConfigureAwait(false); await Task .Delay(_replyWaitTimeout, cancellationToken) .ConfigureAwait(false); observer.OnNext(_endPoints.ToArray()); await Task .Delay(_pollingInterval, cancellationToken) .ConfigureAwait(false); } } finally { await clientChannel .CloseAsync() .ConfigureAwait(false); } } finally { await clientGroup .ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)) .ConfigureAwait(false); } observer.OnCompleted(); } catch (OperationCanceledException) { observer.OnCompleted(); } catch (Exception exception) { observer.OnError(exception); } }) .DistinctUntilChanged(endPoints => string.Join(";", endPoints.Select(endPoint => endPoint.ToString())))); }
public IDisposable Run() { ManualResetEvent resetEvent = new ManualResetEvent(false); var subscription = Observable .Create <object>(async(observer, cancellationToken) => { try { Bootstrap serverBootstrap = new Bootstrap(); MultithreadEventLoopGroup serverGroup = new MultithreadEventLoopGroup(1); try { serverBootstrap .Group(serverGroup) .ChannelFactory(() => new SocketDatagramChannel(_addressFamily)) .Option(ChannelOption.Allocator, PooledByteBufferAllocator.Default) .Option(ChannelOption.SoReuseaddr, true) .Option(ChannelOption.IpMulticastLoopDisabled, false) .Handler(new ActionChannelInitializer <IChannel>(channel => { channel.Pipeline.AddLast(this); })); SocketDatagramChannel serverChannel = (SocketDatagramChannel)await serverBootstrap .BindAsync(IPAddress.Any, _discoveryServerPort) .ConfigureAwait(false); try { TaskCompletionSource <object> tcs = new TaskCompletionSource <object>(); using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken), false)) { resetEvent.Set(); await tcs.Task.ConfigureAwait(false); } } finally { await serverChannel .CloseAsync() .ConfigureAwait(false); } } finally { await serverGroup .ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)) .ConfigureAwait(false); } observer.OnCompleted(); } catch (OperationCanceledException) { observer.OnCompleted(); } catch (Exception e) { observer.OnError(e); } }) .Subscribe(); resetEvent.WaitOne(); return(subscription); }