Клиентский сервер UDP: использование через глобальную сеть

У меня есть приложение, которое отправляет данные (сервер) на UDP-клиент. Он отлично работает на том же компьютере и в локальной сети, насколько я знаю, как адрес назначения клиента. Однако в тот момент, когда я делаю это через Интернет, он больше не работает, потому что у него нет адреса конечного компьютера. Вот код сервера:

public ServerSender(String address, Int32 port, int TTL)
{
  m_Address = address;
  m_Port = port;
  m_TTL = TTL;

  Init();
}

private Socket m_Socket;
private IPEndPoint m_EndPoint;
private String m_Address;
private Int32 m_Port;
private Int32 m_TTL;


private void Init()
{
  IPAddress destAddr = IPAddress.Parse(m_Address);

  m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 

  m_EndPoint = new IPEndPoint(destAddr, m_Port);     
}

public void SendBytes(Byte[] bytes)
{
  m_Socket.SendTo(bytes, 0, bytes.Length, SocketFlags.None, m_EndPoint);
}

Вот клиент:

    public void Connect(string strAddress, int port)
    {
        m_Address = IPAddress.Parse(strAddress);
        m_Port = port;

        m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Multicast Socket

        m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);

        m_EndPoint = new IPEndPoint(m_Address, m_Port);

        m_Socket.Bind(m_EndPoint);

        m_Socket.Connect(m_EndPoint);

        IsConnected = true;

        this.DoRead();
    }

    private void DoRead()
    {
        try
        {
            m_Socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), m_Socket);
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }

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

1 ответ

Чтобы подвести итог / развить комментарии немного:

  • У вас есть хост с публичным IP-адресом, то есть напрямую подключенный к инету (ваш "сервер")
  • У вас есть хост без публичного IP-адреса, то есть подключенный к инету через какой-то шлюз / брандмауэр... (ваш "клиент")

Поскольку я не знаю, как много вы знаете о работе в сети: пакеты TCP / UDP упакованы в пакеты IP. IP имеет дело с IP-адресами, TCP и UDP знают о портах, но: TCP-порт 1 и UDP-порт 1 - разные вещи!

Ваша сетевая настройка, вероятно, выглядит следующим образом с некоторыми примерами IP:

|--------|  47.46.43.42              |---------|192.168.0.1       |--------|
| Server |======== The INET =========| Gateway |==================| Client |
|--------|               81.82.83.84 |---------|     192.168.0.100|--------|

Шлюз здесь - это ваш "роутер".

Ваш клиент будет настроен на отправку любого трафика, не принадлежащего локальной сети, к шлюзу (если вы можете просматривать веб-сайты с вашего клиента, он настроен правильно).

Еще раз обратите внимание: сетевые устройства будут доставлять IP-пакеты соответствующим получателям, если IP-адрес назначения принадлежит "их" сети. Они не доставят никому, если IP-адрес назначения неизвестен.

Если ваш клиент пытается отправить UDP-пакет на порт сервера 1, он отправит IP-пакет, который содержит IP-адрес назначения 47.46.43.42 и IP-адрес источника 192.168.0.100, вместе с портом назначения 1 и портом использует для отправки пакета (предположим, порт 2). Шлюз получает пакет, видит IP-адрес назначения и отправляет содержимое IP-пакета в виде нового IP-пакета с (пункт назначения 47.46.43.42:1, источник 81.82.83.84) в дальнейшем. Он должен использовать другой порт UDP для отправки, скажем, 15. Главное здесь: он также запоминает, что отправил пакет с порта 192.168.0.100 на порт 47.46.43.42, его собственный порт 15. Каждый раз, когда приходит пакет UDP на порту 15 из 47.46.43.42 можно предположить, что это какой-то ответ, который должен быть перенаправлен на порт 192.168.0.100.

Затем, если сервер получает пакет, все, что он видит, - это (dest IP 47.46.43.42:1, исходный IP 81.82.83.84:83:15). если он хочет отправить ответ обратно, он отправит IP-пакет с (dest 81.82.83.84:15, источник 47.46.43.42:1). Обратите внимание, что сервер только "видит" шлюз, а не ваш клиент за ним! Шлюз получает пакет, напоминает, что он только что отправил IP-пакет (dest 47.46.43.42:1, источник 192.168.0.100:2), предполагает, что IP-пакет является своего рода ответом, и отправляет новый IP-пакет (dest 192.168.0.100:2, источник 47.46.43.42:1) с контентом, полученным с сервера вашему клиенту.

ПРИМЕЧАНИЕ ОСОБЕННО, что это работает только потому, что шлюз получил пакет от клиента и узнал из этого, что 192.168.0.100 и 81.82.83.84 "разговаривают друг с другом". Только благодаря этому он знает, что делать с пакетами, поступающими с вашего сервера!

Теперь давайте попробуем наоборот. Есть два возможных случая:

  1. Сервер знает IP вашего клиента (192.168.0.100) . Напомним, что этот IP-адрес не известен ни одному устройству в Интернете, поэтому, если он отправляет IP-пакет (dest 192.168.0.100, источник 81.82.83.84), он не достигнет шлюза, поскольку единственные пакеты, достигающие шлюза, - это пакеты с IP-адрес назначения 47.46.43.42 . Эта опция никогда не будет работать.

  2. Сервер знает IP-адрес шлюза и отправляет IP-пакет (пункт назначения 47.46.43.42, источник 81.82.83.84). Этот пакет достигнет шлюза. Но что делать с этим шлюзом? Он никогда не запоминал, что пакеты с IP 81.82.83.84, вероятно, следует пересылать вашему клиенту. Единственный способ узнать шлюз - это если клиент сначала отправит пакет на ваш сервер. Эта опция также не будет работать.

Таким образом, серверу * недостаточно знать IP-адрес клиента, но шлюзу необходимо узнать о "разговоре" между вашим сервером и клиентом. А способ работы вашего шлюза требует, чтобы клиент сначала отправлял пакет, используя именно тот порт для отправки, который вы хотите использовать в дальнейшем. Если ваш сервер должен отправить вашему клиенту UDP-порт 2, клиент должен сначала отправить пакет на сервер с UDP-порта 2.

Ваш шлюз делает NATTING, и вам лучше прочитать об этом немного.

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

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

PS: Вас может удивить, почему ваш клиент может отправлять пакеты на шлюз с неправильным IP-адресом назначения, а ваш сервер не может. Это связано с тем, что на уровне Ethernet ваша локальная сеть представляет собой единую сеть, а Интернет - нет...

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