編輯#2:問題是我愚蠢地讓memset參數順序倒退,所以,我沒有過零我的結構,因此必須在一些很少使用的字段中有一些垃圾值。這大概解釋了爲什麼它最初在我的系統上工作,而不是在客戶上。我不認爲我甚至得到了一個編譯器警告。在UDP連接上sendto()獲取錯誤10049(地址不是avai),但bind()工作
編輯#1:雷米建議我使用InetNtop而不是我自己的小ipv6rev()函數來打印出IPv6地址。我這樣做,並得到基本相同的結果。他的下一個建議是建立一個我將繼續努力的SSCCE。但是,目前,我只是編輯這個來注意如果使用InetNtop()。
我正在編寫的應用程序是一種軟件路由器,我在一個套接字(恰好是IPv4)上獲取數據,然後通過IPv6 UDP將它發送出去。我讓它在我的機器上工作,但是當我在客戶端安裝應用程序時,sendto調用失敗。我最初正在與另一臺機器通信,但爲了使測試儘可能簡單,我將UPD IPv6接收機放在同一臺機器上,並使用自己的IP。用netstat,我似乎看到我正確綁定:
UDP [2620:175:e10:2000:10:90:177:104]:20000 *:*
[NATerator.exe]
UDP [2620:175:e10:2000:10:90:177:fff0]:20000 *:*
[node.exe]
「NATerator」是我的軟件路由器的應用程序,而接收器是一個Java應用程序(node.exe)所以,它們都綁定到端口20000,但到不同的IP地址。所以,大概我應該可以從......發送到......:fff0我會想。
但sendto()失敗,10049.這似乎表明我發送到一個錯誤的IP地址或端口的套接字。所以,我添加了調試消息來打印出IP地址和端口,它看起來像我發送到正確的地址。調試信息打印出來:
2014-09-08 05:17:47.155 NATERATOR 7564 [TID=0x4cdc] - omniSocketThread: socket 2264 received bytes 24. NAT ok, calling sendto() 2620:0175:0e10:2000:0010:0090:0177:fff0 port 20000 {.\NATerator.cpp:669}
2014-09-08 05:17:47.181 NATERATOR 7564 [TID=0x4cdc] - omniSocketThread: Error sending data 10049
這裏是SENDTO前的調試信息的代碼,之後再調用的sendto和調試:
char ipv6String[100];
sockaddr_in6 *ipv6_addr;
ipv6_addr = (sockaddr_in6 *) &to;
InetNtop(AF_INET6, &ipv6_addr->sin6_addr, ipv6String, sizeof(ipv6String));
cpu_debug(CPU_DEBUG_ERROR,
"omniSocketThread: socket %d received bytes %d. NAT ok, calling sendto() IP %s port %d\n",
*csock, bytecount, ipv6String, htons(ipv6_addr->sin6_port));
bytecount = sendto(rtusock, (char *) buffer, bytecount, 0, (const sockaddr *) &to, tolen);
if(bytecount==SOCKET_ERROR)
{
"omniSocketThread: Error sending data %d\n", WSAGetLastError());
continue;
}
注意,「cpu_debug」是一個室內調試記錄器,其操作方式與printf()相同。
我最初打開套接字的代碼就在這裏。我目前沒有設置任何套接字選項。不知道我需要什麼。我只是調用套接字()和bind()像這樣:
rtusock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (rtusock == -1)
{
return(false);
}
in6_addr ipv6addr;
lookupHost(local_ipv6, &ipv6addr);
memset(&sinIPv6, 0, sizeof(sinIPv6));
sinIPv6.sin6_family = AF_INET6;
// sinIPv6.sin6_addr = in6addr_any;
memcpy(&sinIPv6.sin6_addr, &ipv6addr, sizeof(in6_addr));
sinIPv6.sin6_port = htons(rtuport);
sockstatus = bind(rtusock, (struct sockaddr *) &sinIPv6, sizeof(sockaddr_in6));
if(sockstatus == -1)
{
return(false);
}
的lookupHost功能得到填補了in6_addr結構,我認爲必須要工作,因爲nestat顯示綁定的應用程序。 「rtuport」被定義爲20000.因爲它是#define常量,所以我應該在所有上限中創建該名稱。所以,socket()和bind()調用的創建看起來就像是工作。但也許我需要一些套接字選項設置?
無論如何,最後一段相關代碼就是我填寫「to」結構的地方。它被定義爲:
struct sockaddr_storage to;
int tolen;
tolen = sizeof(to);
我有填充的功能:
bool omniNATerator(struct sockaddr_storage *to, USHORT received_dest)
{
struct sockaddr_in6 *ipv6_addr = (sockaddr_in6 *) to;
memset(to, sizeof(sockaddr_storage), 0);
memcpy(&ipv6_addr->sin6_addr, &rtu_to_ipv6_map[received_dest], sizeof(in6_addr));
ipv6_addr->sin6_family = AF_INET6;
ipv6_addr->sin6_port = htons(rtuport);
凡rtu_to_ipv6_map定義如下:
in6_addr rtu_to_ipv6_map[65536];
而且,我有理由相信,該數組中的值是正確的地址,因爲我將它解壓縮回調試消息中,並且它正確地指出了目標地址。
所以,也許我忽略了一些簡單的東西。但是,就我所見,我打開了套接字,我正在發送一個可用且合理的IP地址。 (我可以ping通兩個IP地址,所以它應該可以工作,但它不會。任何想法,我可能會失蹤?如果它是愚蠢的,也許不會downvote我太糟糕,哈哈
哦,我不妨列出從IPCONFIG輸出:
Ethernet adapter IPv6:
Connection-specific DNS Suffix . :
IPv6 Address. . . . . . . . . . . : 2620:175:e10:2000:10:90:177:104
IPv6 Address. . . . . . . . . . . : 2620:175:e10:2000:10:90:177:fff0
Link-local IPv6 Address . . . . . : fe80::cdd7:56a8:1afd:39e9%13
Default Gateway . . . . . . . . . :
因此,任何想法
PS我不是一個專家插座程序員,但,我已經寫了幾個插座相關的應用,與一些?。但是,我知道有很多我不知道。謝謝你的幫助!
我不完全確定是否支持在同一臺計算機上的兩個不同地址之間發送數據包。 (我知道在某些配置中虛擬機無法與主機進行通信,這看起來可能是相關的。)另一方面,它可能是一個bug;如果更改其中一個端口號,它會起作用嗎?也許Windows錯誤地認爲你正試圖向你發送一個數據包。 – 2014-09-06 21:32:40
是的,您可以將數據從一個本地IP發送到同一臺機器上的另一個本地IP。 WinSock在內部處理必要的連接,因此它不通過網絡物理傳輸數據。在VM環境中,您必須使用VM的內置路由器才能在VM和主機之間傳遞數據。請記住,虛擬機作爲一臺獨立的機器運行,因此操作系統會相應地執行操作,這就是虛擬機需要虛擬網絡設置的原因。 – 2014-09-06 21:59:02
@RemyLebeau:我一直在努力記住細節;我認爲如果VM設置爲通過NAT共享主機的IP地址,VM主機通信不起作用。虛擬機可以很好地與本地網絡的其餘部分通話,而不是主機。但是現在我想到了,虛擬機軟件可能已經與WinSock級別以下的網絡堆棧進行了接口連接,並且在任何情況下,與同一個IP地址進行通信都是一個問題,而不是一個不同的問題。您對OP問題的解釋似乎更有可能。 – 2014-09-07 20:32:09