Клиентский сервер 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 "разговаривают друг с другом". Только благодаря этому он знает, что делать с пакетами, поступающими с вашего сервера!
Теперь давайте попробуем наоборот. Есть два возможных случая:
Сервер знает IP вашего клиента (192.168.0.100) . Напомним, что этот IP-адрес не известен ни одному устройству в Интернете, поэтому, если он отправляет IP-пакет (dest 192.168.0.100, источник 81.82.83.84), он не достигнет шлюза, поскольку единственные пакеты, достигающие шлюза, - это пакеты с IP-адрес назначения 47.46.43.42 . Эта опция никогда не будет работать.
Сервер знает 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 ваша локальная сеть представляет собой единую сеть, а Интернет - нет...