Привет всем.
Есть приложение — UDP сервер (Win, на IOCP, C++). Слушает соединения и отправляет результат с помощью WSASendTo.
Упрощенно это выглядит так:
Все хорошо работает, но возникает проблемка, когда в свойствах TCP/IP прописано несколько IP адресов. Т.е. их, например, два: 192.168.0.10 и 192.168.0.11.
Когда клиент шлет запрос UDP-серверу на IP 192.168.0.10, то респонз обратно шлется с того же IP и все работает хорошо.
А вот когда клиент шлет запрос га IP 192.168.0.11, то респонз обратно шлется с IP 192.168.0.10 и клиент его не видит.
Не подскажете, если кто сталкивался, как это можно побороть? У WSASendTo нету к сож. параметра-ip с которого слать
У него есть только сокет,который слушает все интерфейсы (INADDR_ANY). Надо сделать так, чтобы ответ отправлялся с того же ip, на который пришел запрос.
Здравствуйте, KaktusAgava, Вы писали:
KA>Все хорошо работает, но возникает проблемка, когда в свойствах TCP/IP прописано несколько IP адресов. Т.е. их, например, два: 192.168.0.10 и 192.168.0.11. KA>Когда клиент шлет запрос UDP-серверу на IP 192.168.0.10, то респонз обратно шлется с того же IP и все работает хорошо. KA>А вот когда клиент шлет запрос га IP 192.168.0.11, то респонз обратно шлется с IP 192.168.0.10 и клиент его не видит. KA>Не подскажете, если кто сталкивался, как это можно побороть? У WSASendTo нету к сож. параметра-ip с которого слать KA>У него есть только сокет,который слушает все интерфейсы (INADDR_ANY). Надо сделать так, чтобы ответ отправлялся с того же ip, на который пришел запрос.
Проблема широко известна. Был бы это Unix, можно было бы решить опциями приёма и отправки.
Но на таких слабых API, как в Windows, единственный вариант — перебрав адреса на интерфейсах, создать на каждый адрес свой отдельный сокет. То есть в Вашем примере первый слушает на 192.168.0.10, второй — на 192.168.0.11 (и ещё один нужен, наверно, и на 127.0.0.1). API перебрать адреса на интерфейсах известно и доступно. Через какой сокет получен запрос, через такой и отправлять ответ.
Для сравнения, ISC named так делает (перебор адресов и по сокету на адрес) по умолчанию, не рассчитывая на конкретные флаворы (опции для этого в BSD, Linux и SysV взаимно несовместимы).
Здравствуйте, netch80, Вы писали:
N>Проблема широко известна. Был бы это Unix, можно было бы решить опциями приёма и отправки. N>Но на таких слабых API, как в Windows, единственный вариант — перебрав адреса на интерфейсах, создать на каждый адрес свой отдельный сокет. То есть в Вашем примере первый слушает на 192.168.0.10, второй — на 192.168.0.11 (и ещё один нужен, наверно, и на 127.0.0.1). API перебрать адреса на интерфейсах известно и доступно. Через какой сокет получен запрос, через такой и отправлять ответ.
N>Для сравнения, ISC named так делает (перебор адресов и по сокету на адрес) по умолчанию, не рассчитывая на конкретные флаворы (опции для этого в BSD, Linux и SysV взаимно несовместимы).
Это да, можно завести сокет для каждого ip. Но возникают неприятные моменты:
1. Нужно получить как-то все адреса. Пока не знаю как, но наверно решаемо. В принципе, можно заставить пользователя в конфиге перечислить все ip, пока это рабочий вариант.
2. В случае изменения настроек tcp/ip (добавление/удаление ip) нужно не забыть перестартовать сервис (сервер выполнен в виде win-сервиса).
Здравствуйте, KaktusAgava, Вы писали:
KA>Это да, можно завести сокет для каждого ip. Но возникают неприятные моменты: KA>1. Нужно получить как-то все адреса. Пока не знаю как, но наверно решаемо. В принципе, можно заставить пользователя в конфиге перечислить все ip, пока это рабочий вариант.
У меня возникла еще идея — попытаться определить ip-адрес, на который был отправлен udp пакет, и сделать кэш "исходящих" сокетов. Т.е.:
1. приходит пакет например на 192.168.0.10 -> кэш пустой -> создаем сокет s10 -> добавляем в кэш -> отправляем с него респонз.
2. приходит пакет на 192.168.0.11 -> в кэше сокета нет -> создаем сокет s11 -> добавляем в кэш -> отправляем с него респонз.
3. приходит пакет на 192.168.0.10 -> в кэше есть s10 -> отправляем с него респонз.
Но засада в том, что WSARecvFrom позволяет узнать только С какого ip пакет был отправлен, но не НА какой
Здравствуйте, KaktusAgava, Вы писали:
KA>Но засада в том, что WSARecvFrom позволяет узнать только С какого ip пакет был отправлен, но не НА какой
В общем, получилось у меня реализовать свою идею. Вместо WSARecvFrom и WSASendTo пришлось задействовать соответственно WSARecvMsg (есть начиная с XP) и WSASendMsg (есть начиная с Vista).
Здравствуйте, KaktusAgava, Вы писали:
KA>В общем, получилось у меня реализовать свою идею. Вместо WSARecvFrom и WSASendTo пришлось задействовать соответственно WSARecvMsg (есть начиная с XP) и WSASendMsg (есть начиная с Vista).
А примечание в MSDN, что desktop apps only, насколько существенно? У вас же сервис?
Здравствуйте, netch80, Вы писали:
N>А примечание в MSDN, что desktop apps only, насколько существенно? У вас же сервис?
Да. На сервере должно крутиться. Win Server 2008 или 2012.
Хотелось бы, конечно, чтобы и на 2003, но там WSASendMsg нет... Для такого случая сделаю вариант с несколькими сокетами — по одному на ip.
Здравствуйте, netch80, Вы писали:
N>А примечание в MSDN, что desktop apps only, насколько существенно? У вас же сервис?
Нагуглился на stackowerflow.com ответ. А точнее, комментарий к ответу:
"Desktop apps" refers to classic Console, GUI and Services that existed prior to Win8/Metro/Mobile. Metro/Mobile introduced a new API framework that does not apply to classic apps, and restricts some of those classic APIs for apps being migrated to Metro/Mobile.
Здравствуйте, KaktusAgava, Вы писали:
KA>2. В случае изменения настроек tcp/ip (добавление/удаление ip) нужно не забыть перестартовать сервис (сервер выполнен в виде win-сервиса).