2011-07-28 314 views
3

我正在使用UDP編寫一些簡單的客戶端/服務器代碼。該程序工作正常,但如果我只啓動客戶端,recvfrom方法不會阻止。但是,當我刪除sendto方法時,recvfrom開始阻塞。對發生了什麼的任何想法?C++ UDP。爲什麼recvfrom()沒有被阻塞?

下面是客戶端代碼:

int server_length;      /* Length of server struct */ 
    char send_buffer[256] = "hi";   /* Data to send */ 
    time_t current_time;     /* Time received */ 

    while(true) 
    { 

     /* Tranmsit data to get time */ 
     server_length = sizeof(struct sockaddr_in); 
     if (sendto(m_oSocket, send_buffer, (int)strlen(send_buffer) + 1, 0, (struct sockaddr *)&m_oServer, server_length) == -1) 
     { 
      fprintf(stderr, "Error transmitting data.\n"); 
      continue; 
     } 

     /* Receive time */ 

     if (recvfrom(m_oSocket, (char *)&current_time, (int)sizeof(current_time), 0, (struct sockaddr *)&m_oServer, &server_length) < 0) 
     { 
      fprintf(stderr, "Error receiving data.\n"); 
      continue; 
     } 

     /* Display time */ 
     printf("Current time: %s\n", ctime(&current_time)); 

     Sleep(1000); 
    } 

這裏是初始化:

unsigned short m_iPortnumber; 
struct sockaddr_in m_oServer; 
struct sockaddr_in m_oClient; 
SOCKET m_oSocket; 
WSADATA w;        /* Used to open Windows connection */ 
    int a1, a2, a3, a4;      /* Server address components in xxx.xxx.xxx.xxx form */ 

    a1 = 192; 
    a2 = 168; 
    a3 = 2; 
    a4 = 14; 
    m_iPortnumber = 52685; 

    /* Open windows connection */ 
    if (WSAStartup(0x0101, &w) != 0) 
    { 
     fprintf(stderr, "Could not open Windows connection.\n"); 
     exit(0); 
    } 

    /* Open a datagram socket */ 
    m_oSocket = socket(AF_INET, SOCK_DGRAM, 0); 
    if (m_oSocket == INVALID_SOCKET) 
    { 
     fprintf(stderr, "Could not create socket.\n"); 
     WSACleanup(); 
     exit(0); 
    } 

    /* Clear out server struct */ 
    memset((void *)&m_oServer, '\0', sizeof(struct sockaddr_in)); 

    /* Set family and port */ 
    m_oServer.sin_family = AF_INET; 
    m_oServer.sin_port = htons(m_iPortnumber); 

    /* Set server address */ 
    m_oServer.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)a1; 
    m_oServer.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)a2; 
    m_oServer.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)a3; 
    m_oServer.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)a4; 

    /* Clear out client struct */ 
    memset((void *)&m_oClient, '\0', sizeof(struct sockaddr_in)); 

    /* Set family and port */ 
    m_oClient.sin_family = AF_INET; 
    m_oClient.sin_addr.s_addr=INADDR_ANY; 
    m_oClient.sin_port = htons(0); 

    /* Bind local address to socket */ 
    if (bind(m_oSocket, (struct sockaddr *)&m_oClient, sizeof(struct sockaddr_in)) == -1) 
    { 
     fprintf(stderr, "Cannot bind address to socket.\n"); 
     closesocket(m_oSocket); 
     WSACleanup(); 
     exit(0); 
    } 
+2

你如何設置套接字?你能添加相關的代碼嗎? – Hasturkun

+1

難道是因爲你發送給自己,所以「recvfrom()」總是有數據等待它嗎? – paulsm4

+0

嘗試綁定到除0以外的端口。 –

回答

5

sendto可能有多種失敗方式。某些(如arp故障)會在sendto期間導致錯誤。其他的,如ICMP port unreachable,可能會在您下次使用套接字時被報告。

您的recvfrom調用實際上可能會取回爲響應您的傳出數據包而發送的ICMP數據包。

第二個recvfrom塊是否如預期的那樣?

+0

是的,它的確如此。第二recvfrom實際上阻止 –

0

它看起來像你設置服務器套接字和客戶端套接字以同樣的方式。對於服務器來說,初始化看起來不錯,但對於客戶端而言,您需要綁定到端口0.

實際上,對於它們兩個而言,您都可以執行INADDR_ANY(IP 0.0.0.0),它不綁定到特定的接口,而是允許在正確的端口上進行任何連接。

2

需要設置套接字阻塞/非阻塞。

  1. 設置阻斷

 int nMode = 0; // 0: BLOCKING 
 
\t if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR) 
 
\t { 
 
    \t \t closesocket(SendingSocket); 
 
    \t \t WSACleanup(); 
 
     return iRet; 
 
\t }

  • 設置非阻塞
  •   int nMode = 1; // 1: NON-BLOCKING 
     
        \t if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR) 
     
        \t { 
     
         \t \t closesocket(SendingSocket); 
     
         \t \t WSACleanup(); 
     
          return iRet; 
     
        \t }