无阻塞连接 socket 的linux c代码

无阻塞连接 socket 的linux c代码 


static int setsocketnonblock(int sfd)
{
    int flags;

    flags = fcntl(sfd, F_GETFL, 0);
    if (flags < 0) {
        return -1;
    }

    return fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
}


static int opensocketnonblock (const char *host, const char *port, int timeout_ms, char errmsg[128])
{
    struct addrinfo hints;
    struct addrinfo *res, *rp;

    int err, sockfd = -1;

    *errmsg = 0;

    /* Obtain address(es) matching host/port */
    memset(&hints, 0, sizeof(struct addrinfo));

    hints.ai_family = AF_UNSPEC;      /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;  /* We want a TCP socket */
    hints.ai_flags = 0;
    hints.ai_protocol = 0;            /* Any protocol */

    err = getaddrinfo(host, port, &hints, &res);
    if (err != 0) {
        snprintf(errmsg, 128, "getaddrinfo error(%d): %s", err, gai_strerror(err));
        return -1;
    }

    /**
     * getaddrinfo() returns a list of address structures.
     *
     * Try each address until we successfully connect(2).
     * If socket(2) (or connect(2)) fails, we (close the socket and)
     *   try the next address.
     */
    for (rp = res; rp != NULL; rp = rp->ai_next) {
        /**
         * socket()
         *
         *   create an endpoint for communication
         *     https://linux.die.net/man/2/socket
         *   On success, a file descriptor for the new socket is returned.
         *   On error, -1 is returned, and errno is set appropriately.
         */
        sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sockfd == -1) {
            snprintf(errmsg, 128, "socket error(%d): %s", errno, strerror(errno));
            continue;
        }

        /* connect a socket as nonblock mode */
        if (setsocketnonblock(sockfd) != 0) {
            snprintf(errmsg, 128, "fcntl error(%d): %s", errno, strerror(errno));
            close(sockfd);
            continue;
        }

        err = connect(sockfd, rp->ai_addr, rp->ai_addrlen);
        if (err == 0) {
            /* connect success */
            freeaddrinfo(res);
            return sockfd;
        }

        if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINPROGRESS) {
            struct pollfd pfd;
            pfd.fd = sockfd;
            pfd.events = POLLOUT;
            pfd.revents = 0;

            do {
                // dead loop?
                err = poll(&pfd, 1, timeout_ms);
            } while(err == 0);

            if (err == -1) {
                snprintf(errmsg, 128, "poll errno(%d): %s", errno, strerror(errno));
                close(sockfd);
                continue;
            }

            if (pfd.revents & POLLERR) {
                snprintf(errmsg, 128, "poll POLLERR");
                close(sockfd);
                continue;
            }

            /* success */
            freeaddrinfo(res);
            return sockfd;
        }

        snprintf(errmsg, 128, "connect errno(%d): %s", errno, strerror(errno));
        close(sockfd);
    }

    if (! errmsg[0]) {
        snprintf(errmsg, 128, "bad address %s:%s", host, port);
    }

    freeaddrinfo(res);
    return -1;
}

 

你可能感兴趣的:(linux,c)