2015-08-02 2 views
0

Привет мой вопрос прост:UDP Порт источника отличается от клиента getsocketname() и сервера RECV()

Я пытаюсь установить UDP соединение через соединение TCP (Поскольку несколько клиентов, подключенных через несколько каналов на сервер и я хочу идентифицировать тех же клиентов через основное TCP-соединение)

Я сделал это, создав на клиенте TCP и UDP-сокет и передав локальный порт UDP, назначенный оператором ОС через TCP на сервер. (В Windows я получаю порт после sendto() через getsocketname()). На сервере я использую этот порт для отправки UDP-пакетов этому точенному клиенту. К сожалению, порт, который мне действительно нужно отправить, отличается от локального порта, который я отправил на сервер.

Например:

Мой клиент получает локальный UDP порт 56423, назначенный. Отправляет его на мой сервер через установленное соединение TCP. Сервер пытается отправить UDP-пакеты в этот порт -> Сбой. Когда я использую стандартный способ возврата порта на сервер через recv() в соке UDP, он сообщает об исходном порту 30299. (Я должен заранее отправить UDP-пакеты для этой информации, но я хочу избежать реализации UDP-соединение)

Как это может быть?

Насколько я понимаю, UDP имеет только порт назначения и порт источника. Поэтому он должен работать, отправив локальный порт клиента на сервер. Могут ли быть прокси-сервисы между ними, которые используют альтернативные порты?

Edit: Некоторый код:

На клиенте: (s32 = INT, с8 = голец)

if(m_WinSock == INVALID_SOCKET) 
    return; 

struct sockaddr_storage addr; 
s32 len = sizeof(sockaddr); 

getsockname(m_WinSock, (SOCKADDR*)&addr, &len); 
c8 ipstr[INET6_ADDRSTRLEN + 1]; 
s32 port; 
if(addr.ss_family == AF_INET) 
{ 
    struct sockaddr_in *s = (struct sockaddr_in *)&addr; 
    m_uLocalPort = ntohs(s->sin_port); 
    inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); 
} 
else 
{ // AF_INET6 
    struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; 
    m_uLocalPort = ntohs(s->sin6_port); 
    inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr); 
} 

m_uLocalPort передается через TCP после этого.

На сервере:

SOCKADDR_IN address; 
    ZeroMemory(&address, sizeof(address)); 
    address.sin_addr = addrin; 
    address.sin_port = htons((u16)remoteport); 
    address.sin_family = AF_INET; 

RemotePort это порт, отправленный клиентом.

Используя этот код на сервере после отправки пакета от клиента:

struct sockaddr_storage addr; 
s32 len = sizeof(sockaddr); 
s32 bytes = recvfrom(m_WinSock, m_RecvBuffer, NET_MAX_UDP_SIZE, 0, (SOCKADDR*)&addr, &len); 
m_RecvAddress = *(struct sockaddr_in *)&addr; 

s32 port = ntohs(m_RecvAddress.sin_port); 
printf("recv from port %i\n", port); 

Я получаю совершенно другой порт.

+0

* Как вы отправляете и получаете порт UDP? Вы где-то забыли 'htons' /' ntohs'? Является ли порт '30299' (в вашем примере) источником подключения TCP или целевым портом? –

+0

Кроме того, было бы проще, если бы у сервера был фиксированный номер порта, а клиент просто использовал адрес сервера и номер фиксированного порта в 'sendto'? –

+0

Я отправляю порт через установленное TCP-соединение. Сервер имеет фиксированный номер порта (через bind()), на который клиент отправляет. Я использовал htons/ntohs так, как мне кажется. Он изменяет только порядок байтов, но порядок байтов не является проблемой, посмотрите на байты 56423 и 30299, которые они полностью отличаются. На сервере я хочу отправить UDP pakets правильному клиенту. Для этого мне нужен клиентский (случайный) UDP-порт. Порты, безусловно, являются разъемами UDP. В моем диспетчере задач я вижу, что они привязаны к моему приложению как порты прослушивания UDP. – ecreif

ответ

2

Это не надежный подход к решению проблемы. Например, NAT может мешать и переназначить ваш порт или даже локальный ip, видимый от вашего клиента. Вам также может потребоваться пробивка отверстий udp.

Правильный способ не предполагает никакого отношения к tcp и udp - это разные трубы.

EDIT: Например:

  1. Client connect() к интерфейсу общественного TCP сервера.
  2. Аутентификация
  3. Сервер отправляет клиенту аутентификационный код (cookie).
  4. Клиент sendto() серверный интерфейс udp сервера, с файлом cookie.
  5. Сервер получает sockaddr от recvfrom().
  6. Связь с сервером sockaddr с подключением к realent tcp с использованием файла cookie. Опционально проверьте/ограничьте ip, чтобы предотвратить быковую силу другим.
  7. То есть, теперь у вас есть пара соединений - приемное гнездо tcp вместе с sockaddr для связи udp.

PS. Вы также можете сделать некоторое шифрование в рукопожатии, но это выходит за рамки вопроса.

+0

Я хочу использовать их как разные трубы. Но я хочу общаться с одним и тем же клиентом по этим трубам, как это сделать, кроме моего подхода? – ecreif

+0

У вас должны быть публичные входы (и tcp & udp) на стороне сервера, и пусть клиент инициирует обмен сообщениями индивидуально и связывает их с чем-то вроде файла cookie и ip-адреса. С другой стороны, вы можете указать свой NAT (или маршрутизатор) «пройти через» в диапазоне портов udp и надеяться, что на вашем ISP нет ничего смешного. –

+0

У меня есть публичные входы, например, я публично слушаю TCP-порт 5000, 5001 и UDP 5002. Теперь, когда клиент подключается, я хочу создать объект Peer на моем сервере и сохранить соответствующую информацию о подключении для всех каналов (включая локальную udp порт). Поэтому позже я могу решить, как я передаю данные этому клиенту. Вы говорите, что я должен создать рукопожатие UDP ontop с использованием recv вместо передачи локальных портов через другой канал? А потом попытайтесь выяснить, какая попытка подключения принадлежит клиенту? – ecreif

Смежные вопросы