Какой UdpClient с SocketOptionName.ReuseAddress действительно принимает данные? - PullRequest
0 голосов
/ 28 марта 2019

Мне нужно получить данные по конкретному адресу конечной точки. Но когда я отвечаю на запрос, мне нужно отправить данные с той же конечной точки, на которую были получены данные (в противном случае другая сторона игнорирует их).

Дело в том, что я не хочу обрабатывать запросы последовательно, поэтому один поток получает только данные, чтобы передать их другому потоку, который их обрабатывает и отправляет ответ. AFAIK, один и тот же экземпляр UdpClient не может использоваться одновременно, поэтому единственная идея, которая мне пришла в голову, - создавать новый экземпляр каждый раз, когда я хочу отправить ответ отправителю.

Чтобы добиться того, чего я хочу, я создаю клиента следующим образом ( SocketOptionName.ReuseAddress ):

var udpClient = new UdpClient
{
    Client = CreateBoundUdpSocket()
};

public static Socket CreateBoundUdpSocket()
{
    var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);

    socket.ExclusiveAddressUse = false;
    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

    socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, optionValue: false);

    socket.Bind(new IPEndPoint(IPAddress.Loopback, 1010));
    return socket;
}

Дело в том, что UDP-клиенты, используемые для ответа, создаются только для этой отдельной операции и сразу же удаляются. Как я могу быть уверен, что только первый созданный экземпляр будет принимать данные, а не другие? Я не хочу терять пакеты.

Согласно проведенным мною тестам, только первый экземпляр получает что-либо. Даже когда я установил его приемный буфер на 0, никакой другой экземпляр не получает никаких данных. Только когда я закрою первый экземпляр, следующий созданный получит данные. Похоже, что порядок создания был важен, потому что всякий раз, когда я закрываю экземпляр, который в данный момент получает данные, следующий созданный начинает получать его (не случайный, а следующий).

Короче говоря, могу ли я быть уверен, что только первый созданный мной экземпляр будет получать данные?

- РЕДАКТИРОВАТЬ -

Чтобы уточнить мой общий подход (возможно, неверный):

var server = new UdpClient { Client = CreateBoundUdpSocket() };

while (true)
{
    IPEndPoint sender = null;
    var data = server.Receive(ref sender);

    Task.Factory.StartNew
    (
        (object param) =>
        {
            // [process the request]
            var request = (Tuple<IPEndPoint, byte[]>)param;

            // and send a response
            using (var client = new UdpClient { Client = CreateBoundUdpSocket() })
            {
                var someResponse = new byte[] { };
                client.Send(someResponse, someResponse.Length, request.Item1);
            }
        },
        state: new Tuple<IPEndPoint, byte[]>(sender, data)
    );
}
...