带有UDPClient.EndReceive和ref远程端点参数的Observable.FromAsyncPattern

时间:2010-12-13 20:39:51

标签: c# asynchronous system.reactive

我正在学习反应式扩展并试图重新考虑我的部分代码。

UDPClient.EndReceive需要ref IPEndPoint参数,因此我目前正在使用此功能:

UdpClient receiverUDP = new UdpClient();
receiverUDP.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
receiverUDP.EnableBroadcast = true;
receiverUDP.Client.ExclusiveAddressUse = false;
receiverUDP.Client.Bind(new IPEndPoint(IPAddress.Any, 1234));

IPEndPoint ep = null;
var async = Observable.FromAsyncPattern<byte[]>(receiverUDP.BeginReceive, (i) => receiverUDP.EndReceive(i, ref ep));
var subscr = async().Subscribe(x => Console.WriteLine(ASCIIEncoding.ASCII.GetString(x)));

如果我的订阅者需要访问远程IPEndPoint怎么办?在我目前的化身中,我正在使用事件,并传回一个包裹byte[]IPEndPoint的自定义类。我不能为我的生活,用Rx解决如何做到这一点。

2 个答案:

答案 0 :(得分:6)

如果您已经为byte[]IPEndPoint创建了一个包装类,为什么不使用Select将其作为序列返回:

private IObservable<RemoteData> GetRemoteDataAsync()
{
    return Observable.Defer(() => 
    {
        UdpClient receiverUDP = new UdpClient();
        receiverUDP.Client.SetSocketOption(SocketOptionLevel.Socket, 
            SocketOptionName.ReuseAddress, true);
        receiverUDP.EnableBroadcast = true;
        receiverUDP.Client.ExclusiveAddressUse = false;
        receiverUDP.Client.Bind(new IPEndPoint(IPAddress.Any, 1234));

        IPEndPoint ep = null;
        return Observable.FromAsyncPattern<byte[]>(
                   receiverUDP.BeginReceive, 
                   (i) => receiverUDP.EndReceive(i, ref ep)
               )()
               .Select(bytes => new RemoteData(bytes, ep));
    });
}

答案 1 :(得分:3)

对于其他任何人来说,使用ReceiveAsync进行此操作的方式稍微简单一些,更现代化:

public static IObservable<UdpReceiveResult> UdpStream(IPEndPoint endpoint)
{
    return Observable.Using(() => new UdpClient(endpoint),
        udpClient => Observable.Defer(() =>
            udpClient.ReceiveAsync().ToObservable()).Repeat());
}

您可以使用IPAddress.Any:

调用它
var stream = UdpStream(new IPEndPoint(IPAddress.Any, 514));

然后使用Select将流投影到您想要的任何类型。