Reputation: 12700
What happens if I do (pseudo-code below):
s = socket
bind s
fork ....
(... at child ...)
listen s
conn = accept s
? Should I use instead:
s = socket
bind s
listen s
fork ....
conn = accept s
?
Which one is correct? Also, do I need to set any options on the socket for this particular scenario?
Upvotes: 2
Views: 469
Reputation: 20738
On Linux (since 3.9) (and Mac OS and FreeBSD and possibly others), you also have the option of using SO_REUSEPORT
.
// _DEFAULT_SOURCE for htobe16 for the port number, you may need _BSD_SOURCE instead
#define _DEFAULT_SOURCE
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <endian.h>
int main() {
struct sockaddr_in6 sa;
int v = 1;
// prepare ipv6 address [::]:1345
memset(&sa, 0, sizeof(sa));
sa.sin6_family = AF_INET6;
sa.sin6_port = htobe16(1345);
int s = socket(AF_INET6, SOCK_STREAM, 0);
perror("socket");
// the key point: enable SO_REUSEPORT
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v));
perror("setsockopt");
// from this point on just plain old socket use
bind(s, (struct sockaddr*)&sa, sizeof(sa));
perror("bind");
listen(s, 0);
perror("listen");
while (1) {
int conn = accept(s, NULL, NULL);
perror("accept");
close(conn);
perror("close");
}
return 0;
}
The advantage of this approach is that no parent/child relationship is required between the processes. Also, the manpage (setsockopt(7)
) suggests that this has performance improvements over traditional approaches.
In this scenario, you can fork before the call to socket
. The only requirement is that all involved processes set SO_REUSEPORT
on their socket and share the same effective UID.
Upvotes: 1
Reputation: 58681
Which one is correct [, calling
listen()
before or afterfork()
]?
Calling listen()
before the fork()
is correct. The effect of listen()
is to mark the underlying socket as ready for connections with a connection backlog. It need only be called once.
I'd label the other approach "incorrect" from the perspective of code quality, in that it's redundant and confusing.
While it's not harmful to call listen()
repeatedly, it's quite dubious. The specification does not say what happens when a subsequent call is made, merely that a connection-oriented socket shall "maintain a queue of outstanding connection indications", that is, a backlog of pending connections. Would a subsequent call be able to change the size of the backlog? Would you want it to? Indeed, not all operating systems even let you query the size of the backlog (FreeBSD has, e.g., SO_LISTENQLIMIT).
Upvotes: 2