Digamos que eu crie um servidor TCP multithread simples como este:
int server_fd = socket(/* args */);
setsockopt(server_fd, /* other args... */);
bind(server_fd, /* other args... */);
listen(server_fd, backlog);
while (1) {
int client_fd = accept(server_fd, /* other args... */);
if (fork() == 0) {
// handle client request
close(client_fd);
exit(0);
}
}
Um servidor como esse deve ser capaz de lidar com muitos clientes, mas o que acontece se um cliente malicioso executar o handshake TCP inicial extremamente lentamente? Durante isso, o servidor ainda será capaz de aceitar outros clientes legítimos, ou o cliente lento proíbe isso, já que a chamada para accept()
está bloqueando?
Para esclarecer minha pergunta:
O que a chamada faz accept()
por baixo dos panos? Ela simplesmente pega o próximo soquete de entrada e o prepara para comunicação estabelecendo um descritor de arquivo, ou ela está se comunicando ativamente com o cliente para completar o handshake? O processo de esperar por um handshake TCP afeta outras conexões de entrada?
Em SOs comuns, o handshake TCP é feito pelo kernel do SO, que pode manipular múltiplos handshakes pendentes em paralelo. Somente quando o handshake TCP é feito com sucesso ele é colocado na fila de conexões estabelecidas, onde pode ser recuperado com
accept
.Observe que algumas pilhas TCP de espaço do usuário ou pilhas TCP pequenas, como aquelas encontradas em sistemas embarcados, podem se comportar de maneira diferente.
Note também que, ao contrário do handshake TCP, um handshake TLS (como em SSL_accept ) é geralmente feito no espaço do usuário. Portanto, com seu design multiprocesso ou multithreading, é melhor que seja feito depois do
fork
, para que um peer lento ou com comportamento inadequado não bloqueie handshakes TLS paralelos.