Tôi đang thử nghiệm với ổ cắm IPv6, đặc biệt là khả năng "ngăn xếp kép" được cung cấp trên Windows Vista và sau đó, và dường như trên Unix theo mặc định. Tôi thấy rằng khi tôi liên kết máy chủ của tôi với một địa chỉ IP cụ thể, hoặc đến độ phân giải tên máy của máy cục bộ của tôi, tôi không thể chấp nhận kết nối từ máy khách IPv4. Tuy nhiên, khi tôi liên kết với INADDR_ANY, tôi có thể.Kết nối máy khách IPv4 với máy chủ IPv6: kết nối bị từ chối
Vui lòng xem xét mã sau cho máy chủ của tôi. Bạn có thể thấy rằng tôi làm theo lời khuyên của Microsoft tạo ra một ổ cắm IPv6, sau đó thiết lập các cờ IPV6_V6ONLY để zero:
addrinfo* result, *pCurrent, hints;
memset(&hints, 0, sizeof hints); // Must do this!
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // We intend to use the addrinfo in a call to connect(). (I know it is ignored if we specify a server to connect to...)
int nRet = getaddrinfo("powerhouse", "82", &hints, &result);
SOCKET sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
int no = 0;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) != 0)
return -1;
if (bind(sock, result->ai_addr, result->ai_addrlen) == SOCKET_ERROR)
return -1;
if (listen(sock, SOMAXCONN) == SOCKET_ERROR)
return -1;
SOCKET sockClient = accept(sock, NULL, NULL);
Đây là mã cho khách hàng của tôi. Bạn có thể thấy tôi tạo một ổ cắm IPv4 và cố gắng kết nối với máy chủ của tôi:
addrinfo* result, *pCurrent, hints;
memset(&hints, 0, sizeof hints); // Must do this!
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo("powerhouse", "82", &hints, &result) != 0)
return -1;
SOCKET sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
int nRet = connect(sock, result->ai_addr, result->ai_addrlen);
Kết quả từ cuộc gọi kết nối của tôi luôn là 10061: kết nối bị từ chối.
Nếu tôi thay đổi mã máy chủ của mình thành ràng buộc :: (hoặc chuyển một máy chủ NULL tới getaddrinfo() (cùng một điều)) và thay đổi mã máy khách của tôi để chỉ định máy chủ NULL trong cuộc gọi getaddrinfo(), thì Máy khách V4 có thể kết nối tốt.
Có ai giải thích tại sao không? Tôi đã không đọc bất cứ điều gì mà chúng ta phải chỉ định một máy chủ NULL (do đó sử dụng INADDR_ANY) nếu chúng ta muốn hành vi dual-socket. Điều này không thể là một yêu cầu, bởi vì những gì tôi có một máy chủ multihomed và tôi muốn chấp nhận IPv4 trên chỉ một số các IP có sẵn?
EDIT 15/05/2013:
Đây là tài liệu có liên quan mà đã nhận được tôi bối rối là tại sao mã của tôi thất bại:
Từ Dual-Stack Sockets for IPv6 Winsock Applications
"Windows Vista và sau đó cung cấp khả năng tạo một ổ cắm IPv6 duy nhất có thể xử lý cả lưu lượng IPv6 và IPv4.Ví dụ, một ổ cắm nghe TCP cho IPv6 được tạo ra, được đặt vào hai điểm dừng k mode, và ràng buộc để cổng 5001. Đây dual-stack ổ cắm có thể chấp nhận các kết nối từ khách hàng IPv6 TCP kết nối với cổng 5001 và từ IPv4 TCP client kết nối với cổng 5001. "
" Theo mặc định, một ổ cắm IPv6 được tạo trên Windows Vista và sau đó chỉ hoạt động trên giao thức IPv6. Để tạo ổ cắm IPv6 thành ổ cắm ngăn xếp kép, chức năng setsockopt phải được gọi với tùy chọn ổ cắm IPV6_V6ONLY để đặt giá trị này về 0 trước khi socket bị ràng buộc vào địa chỉ IP. Khi tùy chọn ổ cắm IPV6_V6ONLY được đặt về 0, ổ cắm được tạo cho họ địa chỉ AF_INET6 có thể được sử dụng để gửi và nhận gói đến và từ địa chỉ IPv6 hoặc địa chỉ IPv4 được ánh xạ. (nhấn mạnh mỏ) "
Bạn cần điểm cuối IPv4 cho kết nối IPv4, 'bind' rõ ràng là điểm cuối IPv6 chứ không phải là ký tự đại diện. –
@ Steve-o Tôi không hiểu ý anh là gì, xin lỗi. Bạn có thể làm rõ? – Wad
Binding thực hiện một bộ lọc để chỉ chấp nhận dữ liệu với địa chỉ đích khớp với địa chỉ bị ràng buộc. Các gói IPv4 sẽ có địa chỉ đích IPv4 do đó sẽ bị từ chối. –