异步套接字客户端代码和一些关于getsockopt和错误处理的疑虑

时间:2016-04-15 16:47:05

标签: c++ sockets asynchronous

以下是我最终为异步客户端做的代码:

struct addrinfo *currentAddress = NULL;

void GetAddresses(std::string hostname, int port)
{
    struct addrinfo hints;

    std::cout << "Get adresses for hostname " << hostname << " port " << port << std::endl;

    std::memset(&hints, 0, sizeof(struct addrinfo));

    hints.ai_family = AF_UNSPEC;        /* Allow IPV4 or IPV6 */
    hints.ai_socktype = SOCK_STREAM;    /* Datagram socket */
    hints.ai_flags = 0;
    hints.ai_protocol = 0;              /* Any protocol */

    std::string portStr;
    portStr = std::to_string(port);

    int status = getaddrinfo(hostname.c_str(), portStr.c_str(), &hints, &currentAddress);

    if (status != 0)
    {
        std::stringstream ss;
        ss << "Cannot resolve hostname " << hostname << ". Error: " << gai_strerror(status);
        throw std::runtime_error(ss.str());
    }
}

void StepNextAddress()
{
    currentAddress = currentAddress->ai_next;
}

void Connect(const std::string& address, int port)
{
    /*
     * Get all addresses for connection
     */
    GetAddresses(address, port);

    bool success = false;

    while (currentAddress != NULL)
    {
        int s = socket(currentAddress->ai_family, currentAddress->ai_socktype, currentAddress->ai_protocol);

        if (s == -1)
        {
            freeaddrinfo(currentAddress);
            std::stringstream ss;
            ss << "Error creating socket. Out of resources.";
            throw std::runtime_error(ss.str());
        }

        std::cout << "Socket created: " << s << std::endl;

#ifdef _WIN32
        unsigned long on = 1;
        ioctlsocket(s, FIONBIO, &on); // Make it non blocking
#else
        fcntl(s, F_SETFL, O_NONBLOCK);  Make if non blocking
#endif

        /*
         * Connect to socket
         */
        int status = connect(s, currentAddress->ai_addr, currentAddress->ai_addrlen);

        if (status < 0 && errno != EINPROGRESS)
        {
            freeaddrinfo(currentAddress);
            std::stringstream ss;
            ss << "Error connecting socket to " << address << " port " << port << ".";
            throw std::runtime_error(ss.str());
        }

        /* 
         * Wait socket to get ready to select
         */
        fd_set readSet, writeSet, exceptSet;
        FD_ZERO(&readSet);
        FD_ZERO(&writeSet);
        FD_ZERO(&exceptSet);
        timeval tout;
        tout.tv_sec = CONNECT_TIMEOUT_SECONDS;

        int retval = select (s + 1, &readSet, &writeSet, &exceptSet, &tout);

        if (retval == -1)
        {
            freeaddrinfo(currentAddress);
            std::stringstream ss;
            ss << "Error selecting socket.";
            throw std::runtime_error(ss.str());
        }

        /*
         * Timeout. Try next resources
         */
        if (retval == 0)
        {
            std::cout << "Connection timedout. Trying next resource." << std::endl;
#ifdef _WIN32
            _close(s);
#else
            close(s);
#endif
            StepNextAddress();
            continue;
        }


        /*
         * Wait socket to be ready to work
         */
        int result = 0;
        socklen_t result_len = sizeof(result);

        int sts = getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &result, &result_len);

        if (sts < 0)
        {
            freeaddrinfo(currentAddress);
            std::stringstream ss;
            ss << "Error getting socket option.";
            throw std::runtime_error(ss.str());
        }

        if (result != 0)
        {
            freeaddrinfo(currentAddress);
            std::stringstream ss;
            ss << "Error getting socket resources.";
            throw std::runtime_error(ss.str());
        }
    }

    freeaddrinfo(currentAddress);

    std::cout << "CONNECTED!!!!!!!!!!!!" << std::endl;
}

int main()
{
    Connect("test.test.com", 21);
}

我还不了解selectgetsockopt的使用情况。它们是必要的还是在我的情况下select就足够了?

在这种情况下,select正在发生错误......选择代码出了什么问题?

另外,这里的错误处理怎么样...我尝试连接列表中的下一个地址的唯一情况是超时...这有意义吗?

要完成,我们非常感谢代码中的评论。

0 个答案:

没有答案