0

I am trying to connect to 80 and 800 ports on 1.1.1.1. I expect connect() to fail on 1.1.1.1:800, but instead it blocks my program completely.

I tried using SOCK_NONBLOCK, but doing asynchronous operations on such a small application seems inappropriate.

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>

void foo(uint16_t port) {
  printf("Starting for %d...\n", port);
  int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  
  struct sockaddr_in sockaddr_in;
  sockaddr_in.sin_family = AF_INET;
  sockaddr_in.sin_addr.s_addr = inet_addr("1.1.1.1");
  sockaddr_in.sin_port = htons(port);
  
  printf(
    "connect: %d\n",
    connect(sockfd, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in))
  );

  printf("Errno: %d\n", errno);

  close(sockfd);
}

int main() {
  foo(80);
  foo(800);
}

Output:

Starting for 80...
connect: 0
Errno: 0
Starting for 800...

Hitsuki
  • 31
  • 8
  • 2
    If you don't want socket operations to block, you need to use non-blocking sockets. That's about it, if you want to keep it relatively simple. Another possible workaround is to use threads (or even processes) but that brings with it a different set of problems. Some of which are harder to work around. – Some programmer dude Aug 31 '23 at 18:30
  • @some-programmer-dude Thanks for your reply! Can you recommend a learning resource about this if you know of any? – Hitsuki Aug 31 '23 at 18:33
  • 2
    The "standard" online resource seems to be [Beej's Guide to Network Programming](https://beej.us/guide/bgnet/). For things more specific to threads I don't know. – Some programmer dude Aug 31 '23 at 18:38
  • 1
    After Beej's guide, look into UNIX Network Programming by W. Richard Stevens. – Harith Aug 31 '23 at 18:40
  • @some-programmer-dude @@harith Thanks for helping! – Hitsuki Aug 31 '23 at 18:43
  • @Hitsuki Why not just bite the bullet and make it non-blocking? It's not that many more lines of code. [Example](https://godbolt.org/z/PYd735x8a) – Ted Lyngmo Aug 31 '23 at 19:32
  • 1
    It won't block for more than a minute. If you can't contemplate non-blocking I/O surely you can devise a thread to do the connect?? Or use `alarm()` as mentioned in the duplicate. – user207421 Aug 31 '23 at 23:27

1 Answers1

2

Establishing a TCP connection involves sending a message and receiving a reply.

This obviously isn't instantaneous. If you want to obtain the result of the connection attempt, you will necessarily need to wait for the result, either by blocking, or by using an asynchronous operation.

You're seem to think the first attempt to connect didn't block, but it did. It just didn't block as long. 1.1.1.1 probably actively refused the connection to 80, producing a response in the time it takes to send a packet and receive a reply. But maybe 1.1.1.1 ignores connections to 800 or redirects them to an offline machine, leaving the client without a response until it times out.

There are ways of shortening the timeout here, including some very simple ones.

ikegami
  • 367,544
  • 15
  • 269
  • 518