2012-11-22 37 views
5

Tôi đang cố gắng viết một máy chủ web có thể nghe trên cả địa chỉ IPv4 và IPv6. Tuy nhiên, mã mà tôi viết ban đầu không hoạt động. Sau đó, tôi phát hiện ra rằng cấu trúc IPv6 hoạt động cho cả IPv4 và IPv6. Vì vậy, bây giờ tôi sử dụng cấu trúc IPv6 tuy nhiên, chỉ có các địa chỉ IPv4 hoạt động. Bài đăng này, why can't i bind ipv6 socket to a linklocal address, cho biết thêm server.sin6_scope_id = 5; vì vậy tôi đã làm điều đó nhưng nó vẫn không chấp nhận kết nối telnet IPv6. Bất kỳ sự trợ giúp nào cũng sẽ được đánh giá cao bởi vì tôi hoàn toàn bối rối.
Cảm ơn!Các ổ cắm ràng buộc vào các địa chỉ IPv6

Mã của tôi là dưới đây:

void initialize_server(int port, int connections, char* address) 
{ 
     struct sockaddr_in6 socket_struct; 
     /*Creates the socket*/ 
     if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
     { 
       syslog(LOG_ERR, "%s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     }/*Ends the socket creation*/ 

     /*Populates the socket address structure*/ 
       socket_struct.sin6_family = AF_INET6; 

     if(address == NULL) 
       socket_struct.sin6_addr=in6addr_any; 
     else 
     { 
       inet_pton(AF_INET6, "fe80::216:3eff:fec3:3c22", (void *)&socket_struct.sin6_addr.s6_addr); 
     } 
     socket_struct.sin6_port =htons(port); 
     socket_struct.sin6_scope_id = 0; 
     if (bind(sock_fd, (struct sockaddr*) &socket_struct, sizeof(socket_struct)) < 0) 
     { 
       syslog(LOG_ERR, "%s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     }//Ends the binding. 

     if (listen(sock_fd, connections) <0) 
     { 
       syslog(LOG_ERR, "%s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     }//Ends the listening function 

}//ends the initialize server function. 
+0

những gì tôi biết ipv6 là 64 bit, do đó, máy chủ sử dụng ipv6 phải đang chạy trên hệ điều hành 64 bit. chỉ cần sử dụng ipv4 cho bây giờ, có rất nhiều vấn đề bằng cách sử dụng ipv6 cho đến nay. – GiantHornet

+2

@GiantHornet: IPv6 không phải là 32 bit hoặc 64 bit; nó có thể chạy trên cả hai hệ thống khác. –

+0

@ GiantHornet yea, tôi không nghĩ điều đó đúng vì máy ubuntu của tôi là i686 là 32-bit và có địa chỉ IPv6 – tpar44

Trả lời

7

Bạn đang tạo một ổ cắm trong gia đình AF_INET, nhưng sau đó cố gắng để ràng buộc nó vào một địa chỉ trong gia đình AF_INET6. Chuyển sang sử dụng AF_INET6 trong cuộc gọi của bạn tới socket().

+0

Cảm ơn gợi ý nhưng nó vẫn không hoạt động ... – tpar44

+0

Làm cho thay đổi đó làm cho nó hoạt động cho tôi. – qqx

+0

chỉ cần ra khỏi sự tò mò bạn sử dụng 'telnet fe80 :: 216: 3eff: fec3: 3c22% eth0 8080' để kiểm tra nó? – tpar44

6

Nói "server.sin6_scope_id = 5;" là tùy ý. Tôi đã chiến đấu với một thời gian này bản thân mình và phát hiện ra bạn cần phải sử dụng phạm vi thực tế của giao diện thực tế mà bạn muốn ràng buộc. Nó có thể được tìm thấy với một chức năng ít quan sát nhưng hữu ích.

#include <net/if.h> 
server.sin6_scope_id=if_nametoindex("eth0"); 

Tất nhiên, mã hóa nó vào một bộ điều hợp cụ thể là mã hóa không đúng, khó coi. Một giải pháp hoàn chỉnh hơn là lặp qua tất cả chúng và khớp với địa chỉ ip mà bạn đang ràng buộc. Sau đây là không hoàn hảo ở chỗ nó không tài khoản cho quirks như có địa chỉ không kinh điển và hai adapter với cùng một ip, vv Nhưng besoverall, chức năng mẫu này hoạt động tuyệt vời và sẽ giúp bạn bắt đầu.

#include <string.h> // strcmp 
#include <net/if.h> // if_nametoindex() 
#include <ifaddrs.h> // getifaddrs() 
#include <netdb.h> // NI_ constants 

// returns 0 on error 
unsigned getScopeForIp(const char *ip){ 
    struct ifaddrs *addrs; 
    char ipAddress[NI_MAXHOST]; 
    unsigned scope=0; 
    // walk over the list of all interface addresses 
    getifaddrs(&addrs); 
    for(ifaddrs *addr=addrs;addr;addr=addr->ifa_next){ 
     if (addr->ifa_addr && addr->ifa_addr->sa_family==AF_INET6){ // only interested in ipv6 ones 
      getnameinfo(addr->ifa_addr,sizeof(struct sockaddr_in6),ipAddress,sizeof(ipAddress),NULL,0,NI_NUMERICHOST); 
      // result actually contains the interface name, so strip it 
      for(int i=0;ipAddress[i];i++){ 
       if(ipAddress[i]=='%'){ 
        ipAddress[i]='\0'; 
        break; 
       } 
      } 
      // if the ip matches, convert the interface name to a scope index 
      if(strcmp(ipAddress,ip)==0){ 
       scope=if_nametoindex(addr->ifa_name); 
       break; 
      } 
     } 
    } 
    freeifaddrs(addrs); 
    return scope; 
} 
Các vấn đề liên quan