Я работаю над простой системой обмена сообщениями UDP, и у меня это работает в основном. Структура состоит в том, чтобы иметь 1 сервер, который просто передает сообщения всем клиентам, которые прослушивают определенный порт (его просто для использования в локальной сети или специальной сети, не подключенной к Интернету, хотя мой тестовый компьютер в настоящее время подключен к сети). Моя проблема в том, что каждый раз, когда я отправляю сообщение, клиент получает 2 копии. На данный момент я не устанавливаю целевой IP в качестве подсети, поэтому, возможно, это проблема:Получение нескольких входящих сообщений для одной отправки
(Примечание: Я знаю, что нарушаю стандартную терминологию клиент-сервер, потому что мой «клиент» является обязательным конкретный порт, но неся со мной).
Так вот как мой сервер определяет целевой данные: открывает
d_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(d_socket == -1)
{
printf("\nError in creating socket");
return false;
}
//socket option set to 1 because we are setting the SO_BROADCAST setting to true
//MSDN says to use int for boolean option types.
int l_socket_option = 1;
setsockopt(d_socket,
SOL_SOCKET,
SO_BROADCAST,
(char*)&l_socket_option,
sizeof(int));
//Zero out the broadcast address member to initialize it
memset(&d_broadcast_address,
0,
sizeof(d_broadcast_address));
//Specify that
d_broadcast_address.sin_family = AF_INET;
d_broadcast_address.sin_port = htons(34444);
d_broadcast_address.sin_addr.s_addr = INADDR_BROADCAST;
Моего клиента порт так:
d_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
//Set port so that calls to recvfrom do not block. Instead recvfrom returns an error if no data is present now.
u_long l_no_block_specifier = 1;
int l_socket_control_result = ioctlsocket(d_socket,
FIONBIO,
&l_no_block_specifier);
if(d_socket == -1)
{
printf("\nError in creating socket");
return false;
}
//Zero out the broadcast address member to initialize it
memset(&d_server_address,
0,
sizeof(d_server_address));
//Specify that
d_server_address.sin_family = AF_INET;
d_server_address.sin_port = htons(34444);
d_server_address.sin_addr.s_addr = INADDR_ANY;
d_address_length = sizeof(d_server_address);
//Bind socket and print an error if bind fails.
if (bind(d_socket, (SOCKADDR*)&d_server_address, sizeof(SOCKADDR_IN)) != 0)
{
printf("\nError in binding socket");
}
После того, как порты открыты клиент порождает нить повторно считывает порт. Я написал небольшое тестовое приложение, которое просто отправляет целое число, представляющее последовательность сообщения. Выход этой программы, как показано ниже:
Sending message #0 at time = 4.0 Got message #0 at time = 4.0 Got message #0 at time = 25.0 Sending message #1 at time = 1004.0 Got message #1 at time = 1004.0 Got message #1 at time = 1047.0 Got message #2 at time = 2004.0 Sending message #2 at time = 2004.0 Got message #2 at time = 2064.0 Sending message #3 at time = 3005.0 Got message #3 at time = 3005.0 Got message #3 at time = 3086.0
Я проверил это очень тщательно, и я уверен, что сама программа не случайно распечатывания 2 уведомления для каждого сообщения (кроме временных меток шоу запоздалое прибытие между двумя квитанциями).
Почему это происходит? Я предполагаю, что это связано с тем, что мой тестовый компьютер подключен к Интернету, и поэтому сообщение передается через два разных пути обратно на мой собственный компьютер из-за широковещательной передачи.
EDIT:
Я изменил клиент так, что он связывает порт вещания, используя свой собственный IP-адрес вместо указания INADDR_ANY и это прекратилось дубликат квитанции. Я также обновил сервер для трансляции только в подсети, частью которой он является, но я не думаю, что это повлияло на несколько квитанций.
Вы не указали свой фактический код отправки или чтения, но я бы предположил, что, поскольку вы отправляете в INADDR_BROADCAST (255.255.255.255) вместо определенного широковещательного адреса подсети и привязываете ресивер к 'INADDR_ANY '(0.0.0.0) вместо конкретного сетевого адаптера, скорее всего, вы получаете несколько копий каждого сообщения от разных сетевых адаптеров на приемнике. Вы можете использовать ['WSARecvMsg()'] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms741687.aspx) вместо 'recvfrom()', чтобы определить, какая сетевая карта фактически получает каждый пакет. –
Да, я не вставлял код отправки/получения, потому что это было бы очень много. Когда я делаю ipconfig, я вижу, что у меня есть 2 IP-адреса, 1 из «Подключение локальной сети Ethernet-адаптера», а другой - от «Беспроводное сетевое подключение беспроводной сети». Поэтому я предполагаю, что дополнительное сообщение исходит из того, что у меня есть 2 цели IP на моей машине, чтобы сообщение попало? – Ian