簡體   English   中英

將IPv4客戶端連接到IPv6服務器:連接被拒絕

[英]Connecting IPv4 client to IPv6 server: connection refused

我正在試驗IPv6套接字,特別是Windows Vista及更高版本提供的“雙棧”功能,默認情況下顯然在Unix上。 我發現當我將服務器綁定到特定的IP地址或本地計算機的主機名解析時,我無法接受來自IPv4客戶端的連接。 但是當我綁定到INADDR_ANY時,我可以。

請考慮我的服務器的以下代碼。 您可以看到我遵循Microsoft的建議創建IPv6套接字,然后將IPV6_V6ONLY標志設置為零:

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);

這是我的客戶的代碼。 您可以看到我創建了一個IPv4套接字並嘗試連接到我的服務器:

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);

我的連接呼叫的結果始終是10061:連接被拒絕。

如果我將服務器代碼更改為綁定到::(或將NULL主機傳遞給getaddrinfo()(同樣的事情)),並更改我的客戶端代碼以在getaddrinfo()調用中指定NULL主機,那么V4客戶端可以連接精細。

誰能解釋為什么好嗎? 如果我們想要雙插槽行為,我還沒有讀過任何我們必須指定NULL主機(因此使用INADDR_ANY)的內容。 這不是一個要求,因為我有一個多宿主主機,我只想在一些可用的IP上接受IPv4?

編輯15/05/2013:

這是相關文檔,讓我對我的代碼失敗原因感到困惑:

來自用於IPv6 Winsock應用程序的雙棧套接字

“Windows Vista及更高版本提供了創建單個IPv6套接字的功能,可以同時處理IPv6和IPv4流量。例如,創建用於IPv6的TCP偵聽套接字,進入雙堆棧模式,並綁定到端口5001。堆棧套接字可以接受來自連接到端口5001的IPv6 TCP客戶端和連接到端口5001的IPv4 TCP客戶端的連接。“

“默認情況下,在Windows Vista上創建的IPv6套接字僅在IPv6協議上運行。為了將IPv6套接字轉換為雙棧套接字,必須使用IPV6_V6ONLY套接字選項調用setsockopt函數,以將此值設置為在套接字綁定到IP地址之前為零。 當IPV6_V6ONLY套接字選項設置為零時,為AF_INET6地址族創建的套接字可用於向IPv6地址或IPv4映射地址發送和接收數據包。強調我的)“

IPv4和IPv6是兩個獨立的協議。 無法使用其他協議處理一個協議的數據包。 這就是雙棧概念存在的原因:您的系統同時運行IPv4和IPv6協議棧,同時具有IPv4和IPv6地址等。

操作系統有一個技巧,您可以擁有一個偵聽所有IPv4和IPv6地址的IPv6套接字。 您仍然需要在主機上同時具有兩個地址系列,並且僅在綁定到通配符地址時才有效。 將該套接字綁定到不再起作用的固定地址后,它將僅適用於您綁定的地址。

因此,如果要監聽所有可用地址,則將IPV6_V6ONLY設置為0並監聽通配符地址。 IPv4客戶端將顯示為使用以::ffff:開頭的IPv6地址::ffff:最后32位包含IPv4地址。

如果要綁定到特定地址,則需要將套接字綁定到要偵聽的每個地址。 然后你需要使用ie select(...)來監視那些套接字並響應那些因為有人連接它們而變得活躍的套接字。

此鏈接http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch12lev1sec2.html提供了有關IPv4和IPv6連接的更多信息,

大多數雙棧主機在處理偵聽套接字時應使用以下規則:

  • 偵聽IPv4套接字只能接受來自IPv4客戶端的傳入連接。
  • 如果服務器具有綁定通配符地址的偵聽IPv6套接字並且未設置IPV6_V6ONLY套接字選項(第7.8節),則該套接字可以接受來自IPv4客戶端或IPv6客戶端的傳入連接。 對於來自IPv4客戶端的連接,服務器的連接本地地址將是相應的IPv4映射IPv6地址。
  • 如果服務器具有偵聽IPv6套接字,該套接字綁定了除IPv4映射的IPv6地址以外的IPv6地址,或已綁定通配符地址但已設置IPv6_V6ONLY套接字選項(第7.8節),則該套接字可以接受來自IPv6客戶端的傳入連接只要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM