Home > Net >  What does it mean to "open" an acceptor?
What does it mean to "open" an acceptor?

Time:07-22

In boost.asio, there is a class called an acceptor. The acceptor is used to listen for connection requests on a specific endpoint and open a socket in response to a request.

There are three acceptor constructors I am interested in.

  1. construct an acceptor without opening or binding
explicit basic_socket_acceptor(
    const executor_type & ex);
  1. construct an acceptor and open it
basic_socket_acceptor(
    const executor_type & ex,
    const protocol_type & protocol);
  1. construct an acceptor, open it, and bind it to an endpoint
basic_socket_acceptor(
    const executor_type & ex,
    const endpoint_type & endpoint,
    bool reuse_addr = true);

1 and 3 both make sense. 1 constructs the acceptor in the C sense: allocate memory on the stack, maybe initialize some variables, etc. 3 specifies the endpoint that the acceptor should listen on. Incoming connection requests addressed to the endpoint will be accepted and a connection will be created on a new socket. 2, however, appears to be a middle ground that allows you to set a "protocol type."

I want to say that that "2 allows you to specify more member variables (the protocol) than 1 and less member variables (e.g., IP address and port number) than 3." However, I don't know if it does anything "extra" over setting some member variables (does it engage with the OS or the NIC?).

What does it mean to open an acceptor?

CodePudding user response:

It opens the socket, indeed.

I chose to talk about the constructor to differentiate between 1, 2, and 3. A question about the member function open would probably have the same answer as this question.

The question then becomes just what does ::socket do (https://pubs.opengroup.org/onlinepubs/009604499/functions/socket.html):

The socket() function shall create an unbound socket in a communications domain, and return a file descriptor that can be used in later function calls that operate on sockets

So for your practical understanding, it allocates and initializes in-kernel resources[1].

[1] on most operating systems, userland TCP stacks exists though

CodePudding user response:

Do you know the underlying logic of accepting incoming networking connections with BSD sockets?

The steps, if you write them manually, are:

  1. open a socket with socket()

    just like opening a file, and you get an integer descriptor you can use with read(), write(), close() etc.

  2. bind the socket to a network address with bind()

    unlike a file, the socket descriptor is not associated with anything outside your process until you do this

  3. tell the OS you want to listen for connections on this socket, with listen()

    until this point, it could still be used as an outgoing connection, although it's unusual to bind the source address explicitly

  4. start accepting incoming connection requests by calling accept()

So when you open an acceptor, you're asking the OS for a socket and saving the descriptor to a member variable.

When you bind an acceptor, you're just asking the OS to link that socket to an address (but there may be a member variable tracking its state as well, so the acceptor remembers this has been done).

Note that the "middle ground" passes a protocol type, which is needed to open a socket (it corresponds exactly to the arguments to socket()), but it doesn't have an address (or endpoint), so it can't bind that socket yet.

  • Related