Я пытаюсь реализовать timeout
в функции recvfrom()
.
Для этого я использую функцию select()
. Я беру код из большого интернета, но не знаю почему, моя программа вылетает, когда я ее использую. Я запускаю этот сервер в сети, если это может помочь. Вот что я пытаюсь сделать:
...
// Setup timeval variable
timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
// Setup fd_set structure
fd_set fds;
FD_ZERO(&fds);
FD_SET(id_de_la_socket, &fds);
// Return value:
// -1: error occurred
// 0: timed out
// > 0: data ready to be read
int retval = select(id_de_la_socket+1, &fds, NULL, NULL, &timeout);
if(retval == -1){
printf("Error");
return NULL;
}
else if(retval == 0){
printf("Timeout");
return NULL;
}
else{
nombre_de_caractere=recvfrom(id_de_la_socket,buffer,1515,/*MSG_PARTIAL*/0,(struct sockaddr*)&information_sur_la_source,&tempo);
...
До попытки реализовать timeout
все работало нормально, мой recvfrom()
был в блочном режиме. Поэтому я думаю, что проблема связана с этим кодом, который я добавляю. Может быть, это параметр функции, которую я плохо понимаю.
Спасибо за вашу помощь.
РЕДАКТИРОВАТЬ: Полный код:
#include "serveur.h"
#include <unistd.h>
#include <fcntl.h>
serveur::serveur()
{
}
StructureSupervision::T_StructureSupervision* serveur::receiveDataUDP(){
WSADATA initialisation_win32;
int erreur;
int tempo;
int nombre_de_caractere;
char buffer[65535];
SOCKET id_de_la_socket;
SOCKADDR_IN information_sur_la_source;
erreur=WSAStartup(MAKEWORD(2,2),&initialisation_win32);
if (erreur!=0)
printf("\nDesole, je ne peux pas initialiser Winsock du a l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nWSAStartup : OK");
id_de_la_socket=socket(AF_INET,SOCK_DGRAM,0);
if (id_de_la_socket==INVALID_SOCKET)
printf("\nDesole, je ne peux pas creer la socket du a l'erreur : %d",WSAGetLastError());
else
printf("\nsocket : OK");
information_sur_la_source.sin_family=AF_INET;
information_sur_la_source.sin_addr.s_addr = inet_addr("10.100.13.129"); // Ecoute sur toutes les IP locales
information_sur_la_source.sin_port=htons(4000); // Ecoute sur le port 4000
erreur=bind(id_de_la_socket,(struct sockaddr*)&information_sur_la_source,sizeof(information_sur_la_source));
if (erreur!=0)
printf("\nDesole, je ne peux pas ecouter ce port : %d %d",erreur,WSAGetLastError());
else
printf("\nbind : OK \n");
tempo=sizeof(information_sur_la_source); // Passe par une variable afin d'utiliser un pointeur
// Setup timeval variable
timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
// Setup fd_set structure
fd_set fds;
FD_ZERO(&fds);
FD_SET(id_de_la_socket, &fds);
// Return value:
// -1: error occurred
// 0: timed out
// > 0: data ready to be read
ULONG NonBlock = 1; ioctlsocket(id_de_la_socket, FIONBIO, &NonBlock);
int retval = select(id_de_la_socket+1, &fds, NULL, NULL, &timeout);
if(retval == -1){
printf("Error");
return NULL;
}
else if(retval == 0){
printf("Timeout");
return NULL;
}
else{
nombre_de_caractere=recvfrom(id_de_la_socket,buffer,1515,/*MSG_PARTIAL*/0,(struct sockaddr*)&information_sur_la_source,&tempo);
buffer[nombre_de_caractere]=0; // Permet de fermer le tableau apr�s le contenu des data, car la fonction recvfrom ne le fait pas
//printf("\nVoici les donnees : %s",buffer);
StructureSupervision::T_StructureSupervision *structureReception = (StructureSupervision::T_StructureSupervision *) buffer;
std::cout << "Voici le numero de Statut Ground Flight : " << structureReception->SystemData._statutGroundFlight;
erreur=closesocket(id_de_la_socket);
if (erreur!=0)
printf("\nDesole, je ne peux pas liberer la socket du a l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nclosesocket : OK");
// ********************************************************
// Quitte proprement le winsock ouvert avec la commande WSAStartup
// ********************************************************
erreur=WSACleanup(); // A appeler autant de fois qu'il a �t� ouvert.
if (erreur!=0)
printf("\nDesole, je ne peux pas liberer winsock du a l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nWSACleanup : OK");
return structureReception;
}
}
select
-1. Добавьте что-то вродеint retval = select(...) ;
и посмотрите на errno ifretval == -1
, как в примере с человеком: linux.die.net /man/2/выбрать - person Holt   schedule 01.07.2014select
, но просматривая примеры Google с сокетом, я нашел это winsocketdotnetworkprogramming.com/winsock2programming/, немного отвратительно, но с использованием неблокирующего сокета, поэтому просто интересно, может ли это быть причиной сбоев. Может быть, вам стоит проверить и посмотреть, что произойдет. - person Holt   schedule 01.07.2014buffer
? - person unwind   schedule 01.07.2014nombre_de_caractere
перед вызовомrecvfrom()
? Вы заменяете это значение возвращаемым значениемrecvfrom()
, что звучит немного пугающе. - person unwind   schedule 01.07.2014int nombre_de_caractere; char buffer[nombre_de_caractere] = 0;
? Если да, то можете ли вы обнаружить там проблему? - person unwind   schedule 01.07.2014ULONG NonBlock = 1; ioctlsocket(ListenSocket, FIONBIO, &NonBlock);
и проверить возвратioctlsocket
с SOCKET_ERROR на ошибку. - person Holt   schedule 01.07.2014nombre_de_charactere
перед вызовомrecvfrom
? Этот номер важен для распределенияbuffer
. Когда есть неопределенное значение, у вас неопределенное поведение. Ваша версия безselect
просто случайно работает.nombre_de-charactere
ДОЛЖЕН быть 1515 или выше. Если это не выполняется, вы можете получить переполнение буфера. - person harper   schedule 01.07.2014