调用accept()会导致WSAEFAULT 10014错误地址

时间:2015-07-27 16:55:39

标签: c++ c networking tcp winsock2

我正在使用MinGW编译器和winsock2 API为Windows编写自定义TCP服务器。

我有这段代码:

TCPSocket TCPSocket::accept() {

    TCPSocket clSocket;
    struct sockaddr_in clAddr;
    socklen_t clAddrSize;

    clAddrSize = sizeof(clAddr);

    clSocket.shared->sockFd = ::accept(shared->sockFd, (struct sockaddr *)&clAddr, &clAddrSize);
    if (clSocket.shared->sockFd < 0) {
        printf("failed to accept incoming connection (code: %d)\n", WSAGetLastError());
        throw SocketException(6, "failed to accept incoming connection");
    }

    clSocket.shared->buffer = new byte [BUFFER_SIZE];
    clSocket.shared->curPos = clSocket.shared->endPos = clSocket.shared->buffer;

    return clSocket;

}

但是在调用accept()之后我得到了

failed to accept incoming connection (code: 10014)

根据MSDN:

  

WSAEFAULT   10014   地址不好。       在尝试使用调用的指针参数时,系统检测到无效的指针地址。如果应用程序发生此错误   传递无效的指针值,或者缓冲区的长度也是如此   小。例如,如果一个参数的长度,这是一个sockaddr   结构,小于sizeof(sockaddr)。

我没有看到,这些指针如何变坏,它们都直接解决了局部变量。 clAddrSize已初始化,shared->sockFd在另一个函数中初始化

void TCPSocket::listen(uint16_t port, int backlog) {

    struct addrinfo * ainfo;
    char portStr[8];
    int res;

    if (shared->sockFd != -1)
        logicError(1, "socket already initialized, need to close first");

    snprintf(portStr, sizeof(portStr), "%hu", (ushort)port);
    if (getaddrinfo("localhost", portStr, NULL, &ainfo) != 0)
        systemError(2, "failed to retrieve info about localhost", false);

    shared->sockFd = socket(ainfo->ai_family, SOCK_STREAM, IPPROTO_TCP);
    if (shared->sockFd < 0)
        systemError(3, "failed to create a TCP socket", false);

    res = bind(shared->sockFd, ainfo->ai_addr, ainfo->ai_addrlen);
    if (res != 0)
        systemError(5, "failed to bind socket to local port", true);

    res = ::listen(shared->sockFd, backlog);
    if (res != 0)
        systemError(6, "failed to set socket to listen state", true);

    freeaddrinfo(ainfo);

}

你看到我忽略了什么吗?

1 个答案:

答案 0 :(得分:1)

好的,感谢CristiFati我发现了问题。 使用这种方式的函数getaddrinfo(&#34; localhost&#34;,portStr,NULL和&amp; ainfo)返回一个IPv6地址。虽然接受了sockaddr_in,这是IPv4地址的结构。

可能有更多方法可以解决,例如

  • 使用sockaddr_in6进行IPv6通信
  • 告诉getaddrinfo只搜索带有第三个参数的IPv4结果
  • 在getaddrinfo
  • 返回的链接列表中获取下一个结果

但我选择以这种方式手动为IPv4协议初始化套接字:

    struct sockaddr_in myAddr;

    memset(&myAddr, 0, sizeof(myAddr));
    myAddr.sin_family = AF_INET;
    myAddr.sin_port   = htons((ushort)port);

    shared->sockFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (shared->sockFd < 0)
        systemError(3, "failed to create a TCP socket", false);

    res = bind(shared->sockFd, (struct sockaddr *)&myAddr, sizeof(myAddr));
    if (res != 0)
        systemError(5, "failed to bind socket to local port", true);

从那以后,一切正常。