Не удается захватить полученную дейтаграмму с помощью udpclient

Я пытаюсь отправить команду UDP на устройство и получить ответ UDP от того же устройства. Отправка работает нормально. Я вижу, как датаграмма отправляется (через WireShark). Я также могу видеть, как датаграмма возвращается с устройства (опять же через WireShark). Время между отправкой команды и получением ответа составляет около 15 миллисекунд.

Код

Byte[] button_click(Byte[] command) 
{
    // Device exists at a particular IP address and listens for UDP commands on a particular port
    IPEndPoint SendingEndpoint = new IPEndPoint(DEVICE_IP, DEVICE_PORT);

    // Device always sends from port 32795 to whatever port the command originated from on my machine
    IPEndPoint ReceivingEndpoint = new IPEndPoint(DEVICE_IP, 32795);

    // Sending client
    sendingClient = new UdpClient();
    sendingClient.Connect(SendingEndpoint);

    // Receiving client
    receivingClient = new UdpClient();
    receivingClient.Client.ReceiveTimeout = RECEIVE_TIMEOUT; // timeout after 4 seconds
    receivingClient.Connect(receivingEndpoint);

    // Send command and wait for response
    Byte[] response = null;
    try
    {
        sendingClient.Connect(DEVICE_IP, DEVICE_PORT);
        sendingClient.Send(command, command.Length);
        response = receivingClient.Receive(ref receivingEndpoint);
    }
    catch (SocketException e)
    {
        // If we timeout, discard SocketException and return null response
    }

    return response;
}

Проблема

Я не могу записать полученную дейтаграмму в своем приложении. Когда я запускаю приведенный выше код, я получаю следующее исключение:

"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."

На StackOverflow есть похожие сообщения, но ни одна из них, похоже, не касается моей ситуации. И я убедился, что мои пакеты не попадают в мой брандмауэр.

Что я делаю неправильно?

0
0
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы используете sendClient для получения, вы можете получить правильное сообщение. Причина в том, что IP состоит из хоста + порта + протокола, когда отправляющая точка подключается к устройству и отправляет сообщение, устройство получает конечную точку и UDP в паре с отправляющей конечной точкой. Когда принимающий клиент пытается получить сообщение, ничего не происходит, поскольку UDP является одноранговым, а порт принимающего клиента должен отличаться от порта отправляющего клиента, в результате получающий клиент ничего не получает. Ниже приведен пример кода для вашей справки.

        IPAddress address;
        IPAddress.TryParse("127.0.0.1", out address);
        IPEndPoint recPoint = new IPEndPoint(address, 13154);
        // IPEndPoint sendPoint = new IPEndPoint(address, 9999);
        UdpClient send = new UdpClient(9999);
        send.Connect(recPoint);
        Byte[] response = null;
        Byte[] command = System.Text.Encoding.Default.GetBytes("NO one");
        try
        {
            send.Send(command, command.Length);
            response = send.Receive(ref recPoint);
        }
        catch(Exception ex) {
            Console.WriteLine(ex.ToString());
        }

Согласно ответу Алекса, я обновляю полный пример кода для справки.

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Net;

namespace console
{
    class Program
    {
        static void Main(string[] args)
        {
            IPAddress address;
            IPAddress.TryParse("192.168.14.173", out address);
            IPEndPoint recPoint = new IPEndPoint(address, 13154);
            IPEndPoint recAnyPoint = new IPEndPoint(IPAddress.Any, 13154);
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.14.174"), 13154);

            // IPEndPoint sendPoint = new IPEndPoint(address, 9999);
            UdpClient send = new UdpClient();
            send.ExclusiveAddressUse = false;
            // no need to use the low level socketoption 
            // send.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            send.Client.Bind(recAnyPoint);
            send.Connect(ipPoint);
            UdpClient receive = new UdpClient();

            receive.ExclusiveAddressUse = false;
            // receive.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            receive.Client.Bind(recPoint);
            receive.Connect(ipPoint);
            Byte[] response = null;
            Byte[] command = System.Text.Encoding.Default.GetBytes("NO one");
            try
            {
                send.Send(command, command.Length);
                response = receive.Receive(ref ipPoint);
                Console.WriteLine(System.Text.Encoding.Default.GetString(response));
            }
            catch(Exception ex) {
                Console.WriteLine(ex.ToString());
            }
        }
    }
}

Спасибо за ваш ответ. Отправляющие и принимающие клиенты могут определенно жить на одном и том же порте (что хорошо, потому что это требуется моему устройству). Я объясню в своем ответе.

Alex Johnson 14.09.2018 18:12

да, он может жить на одном и том же порте, в вашем примере вы используете порт IP +, чтобы отличаться от каждого, ну, я не думал об этом трюке.

FrankX 17.09.2018 02:53
Ответ принят как подходящий

Я решил проблему. Решение требовало двух вещей:

  1. Отправляющие и принимающие клиенты должны были использовать один и тот же локальный порт.
  2. Отправляющий клиент должен был использовать IPEndPoint, объявленный с IPAddress.Any, а принимающий клиент должен был использовать IPEndPoint, объявленный с точным IP-адресом моей локальной машины.

Код

// Create endpoints
IPEndPoint DeviceEndPoint = new IPEndPoint(DEVICE_IP, DEVICE_PORT);
IPEndPoint localEndPointAny = new IPEndPoint(IPAddress.Any, LOCAL_PORT); // helps satisfy point 2
IPEndPoint localEndPointExplicit = new IPEndPoint(IPAddress.Parse(GetLocalIPAddress()), LOCAL_PORT);  // helps satisfy point 2
IPEndPoint incomingEndPoint = null; // Later populated with remote sender's info

// Create sending client
UdpClient sendingClient = new UdpClient();
sendingClient.ExclusiveAddressUse = false; // Going to use same port for outgoing and incoming (helps satisfy point 1)
sendingClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // helps satisfy point 1
sendingClient.Client.Bind(localEndPointAny); // Any outgoing IP address will do

// Create receiving client
UdpClient receivingClient = new UdpClient();
receivingClient.Client.ReceiveTimeout = RECEIVE_TIMEOUT; // 4000 milliseconds
receivingClient.ExclusiveAddressUse = false; // Going to use same port for outgoing and incoming (helps satisfy point 1)
receivingClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // helps satisfy point 1
receivingClient.Client.Bind(localEndPointExplicit); // Must explicitly give machine's outgoing IP address

Код для получения локального IP-адреса можно найти здесь.

Другие вопросы по теме