Несколько дней промучился с отлавливанием бага. Суть в следующем: есть 2 удаленные машины в сети (одна в Украине, другая в Испании). На одной запущен примитивный UPD сервер, на другой - настолько же примитивный клиент. Порядок запуска сервера: WSASturtup() socket() <- UDP сокет bind() connect() <- адрес клиента известен и дальше recv() в цикле, отлавливаем датаграммы. Клиент в свою очередь делает WSAStartup() socket() <- UDP сокет и дальше либо в цикле sendto(), либо вначале bind(), connect(), а потом send() в цикле - это без разницы, работает одинаково. Обнаружен тот факт, что больше половины отосланных таким способом пакетов дублируется(!), т.е. приходит по 2 раза. Определенное количество UDP пакетов теряется, ну и часть приходит по одному, это как бы нормально. Перерыл гуглд/яндекс и так и не нашел зацепок. Самое интересное, что в локальной сети дублирование не происходит, а если на сервере вместо connect()/recv() использовать просто recvfrom() в цикле, то дублей тоже нет совсем, только иногда выпадения. Возможно кто-либо сталкивался с подобным, буду очень благодарен за помощь. На данный момент я могу лишь предположить, что проблема в одном из роутеров между машинами, который зачем-то дублирует UDP пакеты, может быть пытаясь повторно переслать по его мнению умершие, а на самом деле дошедшие до адресата датаграммы. Но все-равно остается непонятным, почему этого не происходит при использовании recvfrom()... Заранее спасибо за Ваши версии.
TheRawGod Дублирование пакетов вполне нормальное поведение сети. Для датаграмм-ориентированных протоколов нужно самому придумывать методы борьбы с потерями и дублированием пакетов. А вообще публикация кода может сильно сократить время гадания на кофейной гуще.
Конечно, вот код сервера: Код (Text): #include <winsock2.h> #include <windows.h> #include <stdio.h> int main(int argc, char *argv[]) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); SOCKET ServerSocket = socket(AF_INET, SOCK_DGRAM, 0); sockaddr_in SockAddr, ClientAddr; ZeroMemory(&SockAddr, sizeof(SockAddr)); SockAddr.sin_family = AF_INET; SockAddr.sin_addr.s_addr = htonl(INADDR_ANY); SockAddr.sin_port = htons((argc > 1) ? atoi(argv[1]) : 2121); int xxx = bind(ServerSocket,(sockaddr*)&SockAddr, sizeof(SockAddr)); ClientAddr.sin_family = AF_INET; ClientAddr.sin_addr.s_addr = inet_addr("_CLiENT_iP_"); ClientAddr.sin_port = htons(0); connect(ServerSocket, (sockaddr*)&ClientAddr, sizeof(ClientAddr)); while (1) { sockaddr_in SockAddrClient; int SockAddrClientLenght = sizeof(SockAddrClient); char RecvBuf[17]; static int old_code = -1; static int code = 0; //recvfrom(ServerSocket, RecvBuf, 17, 0, (sockaddr*)&SockAddrClient, &SockAddrClientLenght); recv(ServerSocket, RecvBuf, 17, 0); code = atoi(RecvBuf); printf("GOT=> %s", RecvBuf); if (old_code+1 != code) printf(" <- !!!"); printf("\n"); old_code = code; } return 0; } //int main() Вот код клиента: Код (Text): #include <winsock2.h> #include <windows.h> #include <stdio.h> int main(int argc, char *argv[]) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); SOCKET OurSocket = socket(AF_INET, SOCK_DGRAM, 0); sockaddr_in ServerAddr; char ServerAddrStr[] = "_SERVER_iP_"; ZeroMemory(&ServerAddr, sizeof(ServerAddr)); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons((argc > 1) ? atoi(argv[1]) : 2121); ServerAddr.sin_addr.s_addr = inet_addr(ServerAddrStr); while (1) { char SendBuffer[17]; static int ID = 0; sprintf(SendBuffer, "%i", ID++); sendto(OurSocket, SendBuffer, 17, 0, (const sockaddr*)&ServerAddr, sizeof(ServerAddr)); printf("SENT=> %s\n", SendBuffer); Sleep(300); } //while (1) return 0; } //int main()
Ну часть взаимодействия построена на UDP была изначально, оно себя оправдывало, такой баг впервые проявился, а менять протокол сейчас - слишком ответственное решение Ок, я согласен что UDP может теоретически допускать дублирование пакетов. Но почему при использовании recvfrom() этого не происходит?