简体   繁体   中英

Non blocking connect to loopback address (127.0.0.1 or localhost)

When I do a non blocking connect to the loopback address from the iOS Simulator (which probably uses the same TCP stack as the Mac and FreeBSD), I see that connect always succeeds, even when the server process isn't running.

I detect that connect succeeded by using select() with zero timeout. So, as long as select() returns 0, I assume that the connection is in progress, if it returns -1 I fail with an error and if it returns 1, the socket is ready for reading (as the server must have responded), and I begin reading after reporting that the connect succeeded.

This works well for all addresses except the loopback. On the loopback select() always returns 1, even when there is no server running. So, I begin reading, which fails and I handle it. But I should have detected this through select()!

You are getting the error before that, right on connect() . Before going to proceed with select() , check that errno is EINPROGRESS and not something else. In *BSD, connections to a non-listening port on a localhost error out (or may error out) immediately.

I just ran a very simple test like this (headers skipped):

int
main(void)
{
    int fd;
    int r;
    struct sockaddr_in remote;
    struct hostent *he;

    he = gethostbyname("localhost");
    if (he == NULL)
            return -1;

    memcpy(&remote.sin_addr, he->h_addr, sizeof(remote.sin_addr));
    remote.sin_port = htons(9671);
    remote.sin_family = AF_INET;

    fd = socket(PF_INET, SOCK_STREAM, 0);
    fcntl(fd, F_SETFL, O_NONBLOCK);

    r = connect(fd, (struct sockaddr *)&remote, sizeof remote);
    if (r < 0) {
            perror("connect");
    }
    return 0;
}

With nothing listening on port 9671 , I got:

  • on Linux: connect: Operation now in progress
  • on FreeBSD: connect: Connection refused

Of course, it is always a good idea to check the error codes of all syscalls (something the example above does not do for simplicity's sake - it's just an illustration, after all).

The problem was that I was relying on select() to tell me if the connect was successful. Select only tells you if something changed on that fd. I should've actually called connect() again on the socket and verify that the if it fails, errno is either EINPROGRESS, ECONN or EALREADY. Except for ECONN, all the other values mean that we should retry; ECONN means it's already connected. Any other errno value means we failed to connect.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM