2014-02-13 44 views
0

我正在使用winsock socket api发送一个端口号非常高的udp数据包,我希望这个数据包在目的地未使用。我的意图是接收一个icmp数据包与目的地不可达/端口不可达消息。我创建了两个套接字,其中一个发送UDP数据包和其他我期待icmp数据包的套接字。发送成功。目的地也返回ICMP回复,这可以在wireshark上验证。现在当我做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'之前和之后的循环内打印输出以确保?因为* if *有错误,所以你有一个无限循环。 –

回答

0

你没有得到“目的地不可达”,除非套接字连接,在UDP感,那么你不通过把它recv(),你可以从后面的send()中得到它作为errno值。

+0

,我已经使用了绑定调用。连接的套接字在这里意味着什么?我相信一个ICMP套接字不能连接。正如我所提到的,我看到一个数据包在wireshark中可用,以响应我早期发送的UDP数据包。我只想知道,为什么数据包卡在内核中,没有传递给我的recv函数?我已经无数次地运行代码,并且偶尔会通过recv函数读取数据,但是在大多数情况下,recv挂起。你会好好阐述你的答案吗? – Abu