Les Sockets et les threads à l'aide de C
Je suis nouveau à deux sockets et les threads. J'ai ce code:
listen(socket_fd, 20);
/* Looooop */
while (1) {
newsocket_fd = accept(socket_fd,
(struct sockaddr *) &client_addr,
&client_len);
if (newsocket_fd < 0) {
error("ERROR on accept");
}
pthread_t thread;
pthread_create(&thread, NULL, run_thread, (void *) newsocket_fd);
pthread_join(thread, NULL);
}
Comment puis-je commencer un nouveau thread pour chaque nouvelle connexion, plutôt que pour chaque demande? Ces fils doivent être démarré lors d'une nouvelle connexion, et ces fils de faut ensuite attendre les demandes, de gérer ces demandes, et enfin de retour lorsque la connexion est fermée. Il devrait y avoir un thread pour chaque connexion. Voici le code pour run_thread
:
void
*run_thread(void *ptr) {
char buffer[256];
bzero(buffer, 256);
int n;
n = read((int) ptr, buffer, 255);
if (n < 0) error("ERROR Reading from socket");
printf("%s\n\n**********\n\n", buffer);
/* Parse buffer and return result */
char *result;
{
/* First, determine command, 4 characters */
/* (much code) */
}
n = write((int) ptr, result, strlen(result));
if (n < 0) error("ERROR Writing to socket");
}
Quelqu'un peut m'aider? Merci.
En utilisant des fils de cette façon n'est pas de l'échelle. Il est préférable d'utiliser une
N'oubliez pas de fermer le socket descripteur de fichier avant de le thread se termine.
select
boucle sur le acceptées connexions.N'oubliez pas de fermer le socket descripteur de fichier avant de le thread se termine.
OriginalL'auteur | 2010-09-15
Vous devez vous connecter pour publier un commentaire.
Vous avez presque eu droit. Le problème est, cependant, que vous rejoignez le fil juste après leur création, et pthread_join est en fait un appel de blocage qui est en attente pour le fil à la fin. Cela signifie que vous ne serez pas en mesure d'accepter les connexions plus alors qu'un thread est en cours d'exécution. Pour résoudre ce problème, vous pouvez utiliser détaché de threads. Vous n'avez pas à joindre détaché de threads. Pour ce faire, vous devez créer de thread attributs à l'aide de pthread_attr_init de la fonction et de transmettre ces attributs à pthread_create.
Être conscient que si vous avez trop de connexions clients, votre application peut manquer de ressources. Ainsi, dans le monde réel, vous avez à gérer un pool de threads. Mais le meilleur des cas pour le protocole TCP/IP du serveur d'applications est d'utiliser asynchronous I/O. Je ne sais pas à propos de C, mais il y a une très bonne bibliothèque en C++ pour les e/S asynchrones application appelée boost::asio.
OriginalL'auteur
Il y a aussi une autre erreur critique.
Vous lancez l'int (void*). Cela ne fait pas de sens. Aussi, vous ne pouvez pas passer l'adresse directement puisque la variable peut être modifiée sur le prochain appel accept() avant que le thread peut copier la variable à sa pile locale. Une façon d'écrire, il serait quelque chose comme ceci:
Avec cette approche, le fil assurez-vous de free() la newsock. E. g un simple
Aussi, je suppose pthread_detach() est très bien, si le programme principal ne se soucie pas de synchronisation avec le fil plus tard avec pthread_join().
J'ai toujours l'impression que c'est plutôt de mauvais goût à la fonte des entiers (void*). La norme dit rien sur int -> (void*) -> int conversion (ou similaire conversions) étant garanti pour fonctionner?
Le coulage d'un "int" à un "void*" et de nouveau de retour est garanti pour fonctionner.
Je vois. Ensuite, j'ai appris quelque chose de nouveau aujourd'hui.
Emmerson: Non, je ne crois pas qu'il est. La conversion d'un entier à un pointeur de type (autre qu'un entier constant 0) a une mise en œuvre définies par le résultat. La conversion d'un pointeur sur un entier de type a une mise en œuvre définies par conséquent, à moins que le résultat est en dehors de la plage de type integer, auquel cas le comportement est indéfini. Il est également noté que "Le résultat n'a pas besoin d'être dans la plage de valeurs de type entier."
OriginalL'auteur Maister
Vlad a de bons conseils.
Notez également que votre newsocket_fd variable est réutilisé pour chaque nouvelle connexion dans votre accepter la boucle, puis un pointeur est transmise à chaque thread de travail. Cela va poser des problèmes lorsque vous commencez à avoir plusieurs clients connectés en même temps.
EDIT: Ignorer ce commentaire, j'ai mal lu l'erreur que vous faisiez. D'autres ont juste des corrections pour le traitement de newsocket_fd.
newsocket_fd
, il en passant la valeur et puis le casting de l'arg de(void*)
àint
dans le fil touche func.OriginalL'auteur Darron