Aplicação usando Socket com clientes simultâneos? Devo usar uma thread para cada cliente?

Para treinar minhas habilidades em C resolvi criar um chat multiusuário usando a sockets e threads. (sys/socket.h e pthread.h)

Por enquanto a aplicação segue assim:
Server: Aguarda múltiplas conexões, isto é, uma thread executa indeterminadamente uma função que aceita novas conexões. cada nova conexão é um socket que é adicionado a uma estrutura do tipo Lista.

Cliente: Se conecta ao server e pede indeterminadamente que o usuário digite mensagens de texto que são enviadas ao servidor, a conexão e o programa cliente é encerrado quando digitado a string “#quit”.

A minha dúvida é a seguinte: para receber as mensagens é utilizado a função recv(), o programa fica travado nesta função enquanto os dados não for recebidos, então para receber mensagens de todos os clientes conectados, eu deveria criar uma thread individual para cada um? E se centenas ou milhares de usuários conectar-se a este server? Terei de criar centenas ou milhares de threads?
Tem algum outro jeito de receber múltiplas mensagens que não usando uma thread individual para cada cliente conectado?

Como sempre, depende.
Se a tua aplicação consegue gerenciar os acessos múltiplos, sem maiores problemas de desempenho, não há necessidade.
Agora se a ideia é crescer o número de conexões ou você tem tido problemas com desempenho, sugiro criar threads separadas

Não cheguei a construir a parte que recebe as mensagens múltiplas, por isso ainda não identifiquei problemas de desempenho.
A dúvida é seguinte:

Há um jeito de receber mensagens de todos os usuários sem usar thread? Já que a função RECV() fica travada enquanto não receber a mensagem

Como ninguém respondeu, resolvi implementar do jeito que pensei mesmo.
Coloquei uma thread que executa indefinidamente aceitando as conexões que são solicitadas, e cada nova conexão que é estabelecida uma nova thread é criada e esta por sua vez fica processando as mensagens.

Não. Provavelmente a função RECV() usa I/O bloqueante, ou seja, ela bloqueia a thread corrente aguardando a operação de entrada terminar. Portanto, é necessário sim que você use uma thread para cada cliente.

A implementação alternativa é usar alguma função de I/O não bloqueante, ou assíncrona. Nesses casos, a thread solicita a operação de entrada e passa o ponteiro para um função de callback, e thread que fez a solicitação continua a sua execução normalmente.

Não é uma questão de desempenho, é questão de design correto mesmo. Se a comunicação com os sockets é feita por I/O bloqueante, então tem que ter uma thread para cada cliente.