在UDP连接中的sendto()上获取错误10049(地址不是avai),但bind()工作

时间:2014-09-06 19:10:03

标签: winapi udp winsock2 sendto

编辑#2:问题是我愚蠢地让memset参数顺序倒退,所以,我并没有把我的结构归零,因此在一些很少使用的字段中必须有一些垃圾值。这可能解释了为什么它最初在我的系统上工作而不是在客户上工作。我认为我甚至没有收到编译器警告。

编辑#1:Remy建议我使用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地址。所以,据推测,我应该能够从...发送......: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()。

我最初打开套接字的代码就在这里。我目前没有设置任何套接字选项。不确定我需要什么。我只是像这样调用socket()和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地址。所以它应该可以工作,但事实并非如此。任何想法我可能会缺少什么?如果它是我的愚蠢,也许不会让我太糟糕了,大声笑。

哦,我不妨列出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。我不是专家套接字程序员。但是,我已经编写了一些与套接字相关的应用程序,以及此站点之前的一些帮助。但是,我知道有很多我不知道。谢谢你的帮助!

1 个答案:

答案 0 :(得分:2)

10049(WSAEADDRNOTAVAIL)表示指定的IP地址无效。很明显,您正在对传递给to的{​​{1}}变量做错了,而您的调试消息可能隐藏了这个问题。

例如,使用sendto()对我来说是可疑的。如果您正确跟踪IP,则不必反转它们,因为它们应该从一开始就采用正确的格式。出于显示目的,您应该使用InetNtop()RtlIpv6AddressToString()之类的功能,而不是手动格式化。

这表明ipv6rev()变量可能以错误的格式开头。看起来to使用to中的数据填充,但您没有显示如何填充该数组,因此很难确定这是否是您的根问题发生的地方。

在这种情况下,您确实需要提供SSCCE,以便其他人可以重现此问题。