2014-02-13 3 views
0

Я использую winsock socket api для отправки пакета udp с очень большим номером порта, который, как я ожидаю, не используется в пункте назначения. Мое намерение состоит в том, чтобы получить обратно один пакет icmp с сообщением недоступного/недоступного порта. Я создал два сокета, один из которых я отправляю пакет UDP и другой сокет, на котором я ожидаю пакет icmp. Передача выполнена успешно. Точка назначения также возвращает ICMP-ответ, это можно проверить на wirehark. Теперь, когда я получаю recv, чтобы получать данные, зависает функция recv. Моя цель - прочитать данные из функции recv, чего не происходит.функция recv (winsock) зависает, хотя данные доступны

Любая помощь для недопонимания/исправления этого поведения будет высоко оценена. Заранее спасибо.

Я прилагаю фрагменты кода здесь ...

void sendPacket(unsigned int socketFd, char *packet, char* remoteIP, char* pingType) 
{ 
    int nsent = -1; 
    int rc = -1; 

    struct addrinfo hints, *res; 

    memset(&hints, 0, sizeof(struct addrinfo)); 

    if (strcasecmp(pingType, "UDP")==0) 
    { 
     hints.ai_flags  = AI_CANONNAME;   /* always return canonical name */ 
     hints.ai_family  = AF_INET;    /* 0, AF_INET, AF_INET6, etc. */ 
     hints.ai_socktype = SOCK_DGRAM;   /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */ 
    } 

    rc = getaddrinfo(remoteIP, NULL, &hints, &res); 
    if (rc != 0) 
    { 
     printf("... Function: %s\tError setting remote address. Exiting. ... \n", __FUNCTION__);  
     exit(-1); 
    } 

    if (strcasecmp(pingType, "UDP")==0) 
    { 
     ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(34344); 
     strcpy(packet, "TIMESTAMP"); 
    } 

    do 
    { 
     if (strcasecmp(pingType, "UDP")==0) 
     { 
      nsent=sendto(socketFd, packet, strlen(packet), 0, (struct sockaddr *)res->ai_addr, (socklen_t)res->ai_addrlen); 
      if (nsent < 0) 
      { 
       continue; 
      } 
     } 
    }while(nsent < 0); 

    return; 
} 


double receivePacket(int socketFd, struct timeval* tvSend, pingReply** lastReplyNode, char* pingType) 
{ 
    ssize_t nRecv = -1; 
    double rc = -1; 
    char recvbuf[1024]; 

    do 
    { 
     nRecv = recv(socketFd, (char *)recvbuf, 1024, 0); 
    } 
    while(nRecv < 0); 

    if (nRecv < 0) 
    { 
     return -1; 
    }  

    rc = processPacket(recvbuf, nRecv, tvSend, lastReplyNode, pingType); 

    if (rc == -1) 
    { 
     printf("... Function: %s\tReceiving error in Data/Protocol ...\n", __FUNCTION__); 
     return -1; 
    } 

    return rc; 
} 

void createSocket(unsigned int *sendSocketFd, unsigned int *receiveSocketFd, char *pingType) 
{ 
#ifdef _WIN32 
    WORD wVersionRequested; 
    WSADATA wsaData; 
    int err; 

    /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ 
    wVersionRequested = MAKEWORD(2, 2); 

    err = WSAStartup(wVersionRequested, &wsaData); 
    if (err != 0) 
    { 
     /* Tell the user that we could not find a usable */ 
     /* Winsock DLL.         */ 
     printf("WSAStartup failed with error: %d\n", err); 
     exit(-1); 
    } 
#endif 

#ifdef _WIN32 
    if (strcasecmp(pingType, "UDP")==0) 
    { 
     int rc = -1; 
     struct sockaddr_in src_address; 
     unsigned long int length; 
     int optval = 1; 
     DWORD Length; 
     OSVERSIONINFO  g_OSVersionInfo; 
     BOOLEAN   g_IsWindowsLonghorn = TRUE; 
     BOOLEAN   g_UseFtosToSetTos = TRUE; 
     int ret, iVal=0; 
     unsigned int sz = sizeof(iVal); 

     g_OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 
     GetVersionEx(&g_OSVersionInfo); 

     if(g_OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) 
     { 
      if(g_OSVersionInfo.dwMajorVersion >= 6) 
      { 
       g_IsWindowsLonghorn = TRUE; 
       g_UseFtosToSetTos = TRUE; 
      } 
     } 

     *receiveSocketFd = INVALID_SOCKET; 
     *receiveSocketFd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
     if (*receiveSocketFd < 0) 
     { 
      printf("Function: %s\tReceiving Socket creation error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError()); 
      exit(-1); 
     } 

     src_address.sin_family=AF_INET; 
     src_address.sin_addr.s_addr=inet_addr("x.x.x.x"); 
     src_address.sin_port=htons(0); 

     rc = bind((SOCKET)*receiveSocketFd,(struct sockaddr *)&src_address,sizeof(src_address)); 
     if (rc < 0) 
     { 
      printf("Function: %s\tReceiving Socket bind error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError()); 
      exit(-1); 
     } 

     iVal = 30000; // in milliseconds 
     ret = setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&iVal, sz); 
     if (ret == SOCKET_ERROR) 
     { 
      printf("%d\n", WSAGetLastError()); 
      return; // Temporary 
     } 

     rc = WSAIoctl((SOCKET)*receiveSocketFd, SIO_RCVALL, &optval, sizeof(optval), NULL, 0, &length, NULL, NULL); 
     if (rc == SOCKET_ERROR) 
     { 
      printf("Function: %s\tReceiving Socket ioctl error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError()); 
      exit(-1); 
     } 
     printf("Function: %s\treceiveSocketFd %d ...\n", __FUNCTION__, *receiveSocketFd); 
    } 
    else 
    { 
     *receiveSocketFd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
     if (*receiveSocketFd < 0) 
     { 
      printf("Function: %s\tReceiving Socket creation error.\tErrNo %d. ...\n", __FUNCTION__, WSAGetLastError()); 
      exit(-1); 
     } 
     printf("Function: %s\treceiveSocketFd %d ...\n", __FUNCTION__, *receiveSocketFd); 
    } 
#endif 

#ifndef _WIN32 
    unsigned int size = 1024;  /* OK if setsockopt fails */ 
    setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 
#else 
    char size[5] = "1024";  /* OK if setsockopt fails */ 
    setsockopt(*receiveSocketFd, SOL_SOCKET, SO_RCVBUF, size, sizeof(size)); 
#endif 

    if (strcasecmp(pingType, "UDP")==0) 
    { 
     *sendSocketFd = socket(AF_INET, SOCK_DGRAM, 0); 
     if (*sendSocketFd < 0) 
     { 
      printf("Send Socket creation error."); 
      exit(-1); 
     } 
     printf("Function: %s\tsendSocketFd %d ...\n", __FUNCTION__, *sendSocketFd); 
    } 

    return; 
} 
+1

Вы уверены, что функция 'recv' блокирует, а не ваш бесконечный цикл при ошибке? Вы действительно должны проверить ошибку и обрабатывать ее надлежащим образом, а не просто цикл навсегда при ошибке, поскольку ошибки не просто исчезают волшебным образом. –

+0

@JoachimPileborg Ошибка отсутствует, функция recv не возвращается. Только когда возвращается функция recv, я могу проверить наличие ошибки. – Abu

+0

Вы отлаживали его? То есть шагнул через код в отладчике, чтобы увидеть, что он действительно блокируется? Или добавлено, например, распечатки внутри цикла до и после вызова 'recv', чтобы убедиться? Потому что * если * есть ошибка, у вас есть бесконечный цикл. –

ответ

0

Вы не получите «назначения недостижим», если сокет не подключен, в UDP смысле, и тогда вы не получите его с помощью recv(), вы получите его как значение errno из, возможно, последующей send().

+0

, как вы можете видеть в коде, я использовал вызов привязки. Что именно вы подразумеваете под подключенным сокетом? Я считаю, что ICMP-сокет не может быть подключен. Как я уже упоминал, я вижу пакет, доступный в wirehark в ответ на мою более раннюю отправку пакета UDP. Все, что я хотел знать, почему пакет застрял в ядре и не доставляется в мою функцию recv? Я запустил код много раз, и время от времени данные считываются функцией recv, но в большинстве случаев recv зависает. Вы любезно уточните свой ответ? – Abu

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