2014-09-06 13 views
1

EDIT # 2 : 문제는 바보 같이 memset 매개 변수 순서가 거꾸로되어있어서 0이 아니 었습니다. 내 구조는 거의 사용되지 않는 필드 중 일부에서 일부 쓰레기 값을 가져야합니다. 아마 처음에는 내 시스템에서 작동하지만 고객에서는 작동하지 않는 이유를 설명 할 것입니다. 컴파일러가 경고를 받았다고 생각지 않는다.UDP 연결에서 sendto()에 오류가 10049 (주소가 아님)가되었지만 bind()가 작동했습니다.

EDIT # 1 : Remy 제안 된 ipv6rev() 함수 대신 InetNtop을 사용하여 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"내 소프트웨어 라우터 응용 프로그램 인, 수신기는 자바 응용 프로그램 인 (node.exe) 따라서는, 그들은 모두 포트에 바인딩 20000,하지만 다른 IP 주소. 그래서, 아마, 나는 ~에서 보낼 수 있어야합니다 ... : 104 ~ : 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()처럼 작동하는 디버거 로거.

처음 소켓을 여는 코드는 여기에 있습니다. 현재 소켓 옵션을 설정하지 않았습니다. 내가 무엇이 필요한지 잘 모르겠다. 난 그냥 지금처럼 소켓()와 바인딩()를 호출 : nestat가 결합 된 응용 프로그램을 보여줍니다 이후

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 구조에 칠을 가져옵니다. "rtuport"는 20000으로 정의됩니다. #define 상수이므로 모든 대문자로 이름을 지정해야합니다. 그래서 socket()과 bind() 호출의 생성은 작업과 같이 보인다. 하지만 아마도 소켓 옵션이 필요할까요?

어쨌든 관련 코드의 마지막 부분은 "to"구조를 채우는 곳입니다. 나는 것을 합리적으로 확신,

in6_addr rtu_to_ipv6_map[65536]; 

그리고 :

이 rtu_to_ipv6_map는 다음과 같이 정의된다
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); 

은 다음과 같습니다 : I가 채우는 기능이

struct  sockaddr_storage to; 
int   tolen; 

tolen = sizeof(to); 

: 그것은 다음과 같이 정의된다 그 배열의 값은 올바른 주소입니다. 디버그 메시지에서 다시 압축을 풀고 대상 주소를 올바르게 표시하기 때문입니다.

그래서 아마도 나는 간단한 것을 간과하고있을 것입니다. 그러나 내가 볼 수있는 것만 큼 가까이서 소켓을 열어 놓았습니다. 사용 가능한 합리적인 IP 주소로 보내고 있습니다. (두 IP 주소 모두 핑 (ping) 할 수 있으므로 작동하지 않아도 될 것입니다. 내가 무엇을 놓칠 지 모르는가? 그리고 그것이 내 바보라면, 너무 나쁘지 않을 수도 있습니다. LOL

오, 나뿐만 아니라 같이 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 나는 몇 가지로, 몇 소켓 관련 응용 프로그램을 작성했습니다하는 전문가 소켓 프로그래머가 아니에요 그러나?.. 이전에이 사이트의 도움을 받았습니다.하지만 모르는 것이 많다는 것을 알고 있습니다. 도움을 주셔서 감사합니다.

+0

같은 컴퓨터에있는 서로 다른 두 주소간에 패킷을 보내는 것이 확실하지 않습니다. (일부 구성에서는 VM이 ​​호스트와 통신 할 수 없다는 것을 알고 있는데, 이는 관련성이있는 것으로 보입니다.) 반면에 그것은 버그 일 수 있습니다. 포트 번호 중 하나를 변경하면 작동합니까? 아마도 Windows는 실수로 자신에게 패킷을 보내려고한다고 생각합니다. –

+0

예, 한 로컬 IP의 데이터를 동일한 시스템의 다른 로컬 IP로 보낼 수 있습니다. WinSock은 필요한 연결을 내부적으로 처리하므로 실제로 네트워크를 통해 데이터를 전송하지 않습니다. VM 환경에서는 VM의 기본 제공 라우터를 사용하여 VM과 호스트간에 데이터를 전달해야합니다. VM은 별도의 시스템으로 작동하므로 OS가 이에 따라 작동하므로 VM에 가상 네트워크 설정이 필요한 이유입니다. –

+0

@RemyLebeau : 세부 사항을 기억하려고 노력해 왔습니다. VM이 NAT를 통해 호스트의 IP 주소를 공유하도록 설정된 경우 VM 호스트 통신이 작동하지 않는다고 생각합니다. VM은 호스트가 아닌 다른 로컬 네트워크와 완벽하게 통신 할 수 있습니다. 그러나 이제는 VM 소프트웨어가 WinSock 수준 아래의 네트워크 스택과 인터페이싱했을 수도 있으며, 어떤 경우에도 동일한 IP 주소로 통신하는 데 문제가 될 수 있습니다. 영업 문제에 대한 귀하의 해석은 훨씬 더 가능성이 높습니다. –

답변

2

1004 9 (WSAEADDRNOTAVAIL)는 지정된 IP 주소가 유효하지 않음을 의미합니다. 따라서 sendto()으로 전달하는 변수 to을 잘못 처리하면 디버그 메시지가 문제를 숨길 가능성이 큽니다.

예를 들어, ipv6rev()의 사용은 저에게 의심 스럽습니다. IP를 올바르게 추적하는 경우 처음부터 올바른 형식이어야하기 때문에 IP를 되돌릴 필요가 없습니다. 표시 목적으로 직접 서식을 지정하는 대신 InetNtop() 또는 RtlIpv6AddressToString()과 같은 기능을 사용해야합니다.

이는 to 변수가 잘못된 형식으로 시작될 가능성이 있음을 나타냅니다. rtu_to_ipv6_map[]의 데이터를 사용하여 to이 채워지는 것처럼 보이지만 그 배열을 채우는 방법을 보여주지 않았으므로 근본 문제가 발생하는 곳인지 확실하게 알기가 어렵습니다.

다른 사람들이 문제를 재현 할 수 있도록 SSCCE을 제공해야하는 상황입니다.

+0

이봐, 레미, 너 어디 안나니? LOL. 저는 많은 델파이를합니다. 적어도 그렇게 익숙해 져서, 당신은 저를 여러 번 도와 줬습니다. 나는 당신의 제안을 주소의 형식화에 사용하고 거기에서 일할 것입니다. – user3681853

+0

레미, InetNtop()을 사용하도록 코드를 변경했으며 동일한 결과를 얻었습니다. 동일한 출력물이 있습니다. 내 질문을 개정판으로 업데이트했습니다. 나는 SSCCE에서 다음으로 일할 것이다. 감사. – user3681853

+0

작은 테스트 프로그램을 만들었습니다. 그래서, 내 메인 프로그램에 뭔가 잘못 됐음에 틀림 없다.memset() 호출에서 매개 변수를 바꿨다는 것을 알았습니다. 여기서 크기와 바이트 값을 바꿨습니다. 아마 그것이 문제이며, 나는 더 시험 할 것이다. 도와 주셔서 감사합니다. – user3681853