2013-01-02 17 views
0

我被我的UDP講話者應用程序卡住了。 目前的目標是初始化服務器,註冊一個客戶端,然後繼續發送一些東西給客戶端。 我的工作我的方式,通過Beej的網絡指南和編碼以下庫實現:UDP Talker在sendto()調用時給出「ai_flags值不好」

這inizializes服務器

int init_udp_server(const char *port_string){ 

    /** Check the input data **/ 
    if(port_string == NULL) 
    port_string = DEFAULT_PORT; 

    /** Get the information for the server **/ 
    memset(&addrinfo_hints, 0, sizeof addrinfo_hints); 
    /* Use either protocol (v4, v6) */ 
    addrinfo_hints.ai_family = AF_UNSPEC; 
    /* Use UDP socket type */ 
    addrinfo_hints.ai_socktype = SOCK_DGRAM; 
    /* Use system IP */ 
    addrinfo_hints.ai_flags = AI_PASSIVE; 

    if((ret = getaddrinfo(NULL, port_string, &addrinfo_hints, &addrinfo_server)) 
     != 0){ 
    printf("Server:getaddrinfo: %s\n", gai_strerror(ret)); 
    return -1; 
    } 

    /** Loop through the list returned by getaddrinfo and get socket **/ 
    for(addrinfo_queue = addrinfo_server; addrinfo_queue != NULL; 
     addrinfo_queue = addrinfo_queue->ai_next){ 
    if((sockfd = socket(addrinfo_queue->ai_family, 
      addrinfo_queue->ai_socktype, addrinfo_queue->ai_protocol)) == -1){ 
     error("Server: get socket failed"); 
     continue; 
    } 
    if(bind(sockfd, addrinfo_queue->ai_addr, addrinfo_queue->ai_addrlen) 
     == -1){ 
     close(sockfd); 
     error("Server: Bind to socket error"); 
     continue; 
    } 
    break; 

    } 
    /* If we got to addrinfo_queue == NULL, we did not get a valid socket */ 
    if(addrinfo_queue == NULL){ 
    error("Server: Could not bind a socket"); 
    return -1; 
    } 
    /* We do not need the addrinfo_server anymore */ 
    freeaddrinfo(addrinfo_server); 
    return 0; 
} 

此註冊客戶端

int udp_server_setup_client(const char *client_addr, const char *port_string, int  client_nr){ 


    /** Check the input data **/ 
    if(port_string == NULL) 
    port_string = DEFAULT_PORT; 
    if(client_addr == NULL){ 
    error("No valid client list"); 
    return -1; 
    } 
    if(client_nr < 0 || client_nr > 7){ 
    error("No valid client Nr."); 
    return -1; 
    } 

    memset(&addrinfo_hints, 0, sizeof addrinfo_hints); 
    /* Use either protocol (v4, v6) */ 
    addrinfo_hints.ai_family = AF_UNSPEC; 
    /* Use UDP socket type */ 
    addrinfo_hints.ai_socktype = SOCK_DGRAM; 

    /* Get the information for the client */ 
    if((ret = getaddrinfo(client_addr, port_string, &addrinfo_hints, 
      &current)) != 0){ 
    printf("Client:getaddrinfo: %s\n", gai_strerror(ret)); 
    return -1; 
    } 
    else{ 
    /* We read out the IP, kind of a nice check to see wheter all went fine */ 
    char ip4[INET_ADDRSTRLEN]; 
    struct sockaddr_in *sa = (struct sockaddr_in*) current->ai_addr; 
    inet_ntop(AF_INET, &(sa->sin_addr),ip4, INET_ADDRSTRLEN); 
    printf("Clients address: %s\n",ip4); 
    addrinfo_clients[client_nr] = current; 
    } 
    return 0; 
} 

最後這是一個書寫

int udp_server_write(const char *buffer, int buffer_size, int client_nr){ 
    /* Sanity check of the input */ 
    if(client_nr > (MAX_NR_CLIENTS - 1) || client_nr < 0){ 
    error("Not a valid client"); 
    return -1; 
    } 
    if(buffer == NULL){ 
    error("Not a valid buffer address"); 
    return -1; 
    } 
    /* Just so we type less */ 
    current = addrinfo_clients[client_nr]; 

    socklen = sizeof current->ai_addr; 
    if((ret = sendto(sockfd, (void*)buffer, buffer_size, 0, 
     (sockaddr*)current->ai_addr, socklen)) == -1){ 
    printf("Failed to send message to client %i\n", client_nr); 
    printf("Error Code: %s\n",gai_strerror(ret)); 
    return -1;  
    } 
    else if(ret < buffer_size){ 
    printf("Wrote only %i of %i bytes\n", ret, buffer_size); 
    return -1; 
    } 
    return ret; 
} 

我叫福這樣

init_udp_server("3334"); 

udp_server_setup_client("192.168.1.5", "3334", 0); 

udp_server_write(send_buf, 256, 0); 

只要SENDTO(nctions)被稱爲我得到一個錯誤: 無法將消息發送給客戶端0 錯誤代碼:爲填上ai_flags 我用gdb檢查它的值錯誤,發現addrinfo中結構被正確填充,並且客戶端的地址是有效的。 任何一個想法在哪裏看?我運行的想法......

感謝,wenzlern

+0

從的getaddrinfo的手冊頁:EAI_BADFLAGS hints.ai_flags包含無效標誌;或者,hints.ai_flags包含AI_CANONNAME,名稱爲NULL。我不知道其中的一個如何適用。 – user1688482

回答

2

當調用sendto(),最後一個參數被設置爲sizeof current->ai_addr,這是不對的。 current->ai_addr定義爲sockaddr*指針,因此sizeof current->ai_addr將始終在32位系統上返回4,在64位系統上返回8。 IPv4地址的大小隻有4個字節,因此sizeof current->ai_addr僅適用於32位系統上的IPv4地址,但32位系統上的IPv6地址和64位系統上的所有地址將始終失敗。您需要使用current->ai_addrlen而不是sizeof

另外,傳遞-1到gai_strerror()無效。它期望您傳遞一個真實的錯誤代碼,例如返回值爲getaddrinfo()getnameinfo()sendto()不會返回實際的錯誤代碼。當它失敗時,您必須在Windows上使用WSAGetLastError()或在其他系統上使用errno以獲取實際的錯誤代碼。

試試這個:

if ((ret = sendto(sockfd, (char*)buffer, buffer_size, 0, (sockaddr*)current->ai_addr, current->ai_addrlen)) == -1) 
{ 
    #ifdef _WIN32 
    ret = WSAGetLastError(); 
    #else 
    ret = errno; 
    #endif 

    printf("Failed to send message to client %i\n", client_nr); 
    printf("Error Code: (%d) %s\n", ret, gai_strerror(ret)); 
    return -1;  
} 
+0

非常感謝!你的更正解決了這個問題。我正在研究一臺64位機器,所以它由於socklen構造而不斷失敗。再次感謝!問候,溫茨勒恩 – user1688482