Bonjour à tous,
Ma question est dans le titre, comment puis-je remplacer STDIN_FILENO sous windows ?
Bonjour à tous,
Ma question est dans le titre, comment puis-je remplacer STDIN_FILENO sous windows ?
Pour ça, le plus simple est de le définir toi-même:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 #ifdef _WIN32 #ifndef STDIN_FILENO #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 #endif #endif
Ok je vais tenter ça, mon but est en fait de rendre mes sockets non bloquants, j'ai vu qu'il y avait aussi la fonction WSAAsyncselect si j'ai bonne mémoire, il ne me reste plus qu'à trouver une doc !
merci.
Si c'est pour utiliser avec select(), laisse tomber. Ca ne fonctionnera pas. De toutes façons, il n'y a pas de descripteurs de fichiers sous Windows. C'est soit des 'handles' (SOCKET, par exemple), soit des adresses de type FILE * pour les flux.
"Tout est ficher" est un concept Unix, non repris par Windows.
Le sockets asynchrones (non-bloquants), c'est compliqué à gérer. Qu'est-ce qui ne va pas avec le mode par défaut ? Si il le faut, utilise les threads. Quel est le problème exactement ?
Je souhaite réaliser un serveur multi clients et je coince un peu ...Qu'est-ce qui ne va pas avec le mode par défaut ?
Et je ne veux pas utiliser de threads.
Je bloque un peu sur l'algo de mon problème du coup car il faut que mon serveur ecoute, tout en gerant les clients déjà connectés.
Ah ? Pourquoi ?
Processus ou threads. Pas trop le choix. La solution avec select() risque d'être très complexe...Je bloque un peu sur l'algo de mon problème du coup car il faut que mon serveur ecoute, tout en gerant les clients déjà connectés.
Quoiqu'il en soit, il n'y a pas du tout besoin de passer en asynchrone...
On me l'impose, et puis si deux threads attaquent la pile en meme temps c'est la pagaille.Ah ? Pourquoi ?
Bref mon problème reste l'algorithme ...
Certes, mais c'est pour ça que chaque thread a sa pile...
Alors tu veux utiliser select(), c'est ça ?Bref mon problème reste l'algorithme ...
Alors il faut une boucle avec select() qui surveille la socket du serveur (déclenchement par accept()) et les sockets clients crées par accept() au fur et à mesure de leur création. Ensuite, à chaque évènement (reception d'un message, par exemple), select() se débloque. Ca va faire une usine à gaz, mais si c'est demandé...
A chaque déconnexion (volontaire, ou send() ou recv() qui retourne 0 ou erreur), il faut fermer le socket client correspondant et le retirer de la liste des sockets surveillés.
Nota : sous Windows, le paramètre 1 de select() est ignoré...
Il y a peut être un exemple sur mon site...
http://emmanuel-delahaye.developpez....tes-reseaux-c/
C'est inexact:
Sous Windows, vu du kernel, tout est "objet Kernel" (donc, vu des programmes utilisateurs, "tout est handle".
De plus, la CRT Microsoft implémente le concept de descripteurs de fichiers, en tant que surcouche par-dessus les handles (et les FILE* sont bien une surcouche par-dessus les descripteurs). Seulement, select() est faite pour marcher avec les sockets et ne supporte pas les descripteurs.
Mais même en faisant un WaitForMultipleObjects() sur le socket (ou plus précisément un WSAEVENT) et l'entrée standard, on se retrouve avec un problème dû à la façon stupide dont l'entrée standard est gérée.
Ca c'est une usine à gaz !Certes, mais c'est pour ça que chaque thread a sa pile...
Je vais essayé de coder ton algo mem si ca reste un peu flou ...
La fonction select() est dur à appréhender !
L'algo donnera un truc de ce genre ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 for(;;) { Server Listen; si accept -> creation client select() ? }
La plupart des serveurs peuvent se contenter d'une boucle basée sur select(), même sous Windows, s'ils n'ont pas besoin de réagir à la console.
C'est à partir du moment où il faut écouter autre chose que des sockets que ça se complique.
Non, il donnera un truc de ce genre-ci:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 SOCKET server = socket(); listen(server); LISTEDECLIENTS clients; for(;;) { fd_set readfds; FD_SET(server); for all clients FD_SET(clients[i]); select(..., readfds, ...); if(FD_ISSET(server)) accept(...) for all clients if(FD_ISSET(clients[i]) recv(clients[i]); }
Non. C'est
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 ouvrir le socket serveur (socket(), bind(), listen()) DO programmer la surveillance des sockets ouverts (FD_SET) select() reagir a l'évènement qui a déclenché select (FD_ISSET) SI reception serveur client := accept(serveur) FIN SI POUR CHAQUE client SI reception err := recv(client, commande) reponse := traitement (commande) err := send (client, reponse) FIN SI FIN POUR CHAQUE FOREVER
Il y a un tutoriel sur l'utilisation des sockets non bloquants ici. L'utilisation de WSAAsyncSelect permet d'avoir un programme bien structuré (sans boucle, sans multi-threading, etc.) mais pour l'utiliser, il faut avoir créé une fenêtre (pas forcément visible ...), donc elle ne peut être proprement utilisée dans une application console à moins d'avoir deux threads : le thread principal et un autre thread pour contenir la fenêtre.
Merci a tous pour ces explications, je regarde ça apres manger
Dans ce cas présent, tous les sockets clients ont été au préalable déclarés et initialisés pour un nombre de clients definit n'est ce pas ?Non, il donnera un truc de ce genre-ci:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 SOCKET server = socket(); listen(server); LISTEDECLIENTS clients; for(;;) { fd_set readfds; FD_SET(server); for all clients FD_SET(clients[i]); select(..., readfds, ...); if(FD_ISSET(server)) accept(...) for all clients if(FD_ISSET(clients[i]) recv(clients[i]); }
tableau : oui
liste chainée : non
initialisé, non. (enfin à INVALID_SOCKET, oui).et initialisés pour un nombre de clients definit n'est ce pas ?
Le nombre de clients peut être variable. Il suffit d'une structure de données souple (tableau dynamique, liste chainée ...)
ceci dit, on ne va peut être pas non plus accepter 500.000 clients en meme temps. Pour une machine donnée, il semnble que 1000 à 10000 soit le maximum (ajuster listen() en conséquence... 100, par exemple. Bien lire la doc...)...
Il ne faut pas oublier les temps de traitement et de réponses... Si c'est du html, en gros, on émet 100 à 1000 caractères pour un reçu...
Franchement, c'est dans ce genre de moments qu'il serait plus simple de programmer en C++: Le C++ propose des conteneurs qui te permettraient facilement de gérer ta liste de clients...
Quant à ta question envoyée en MP (comment retrouver un client à partir d'un socket), ici, je pense que la recherche naïve suffira: Parcourir la liste client par client jusqu'à en trouver un qui a le bon socket. C'est en temps linéaire, et tu auras rarement besoin de faire ça en boucle de toute façon.
Je viens de terminer l'écriture de mon serveur.c
Voilà ce que ca donne : je pense avoir respecter l'algorithme et ça devient plus clair. Cependant lorsque je compile l'erreur renvoyée est "erreur lors du select".
voilà mon code :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 t_serveur serveur; WSADATA wsaData; char Buff[BUFF_SIZE]; int i, max, actuel; int Serveur(int sc, int pa) { switch(sc) { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Constructeur. Service NEW pour Serveur. //Création du serveur. case SERVEUR_NEW : if(WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { Fin("Initialisation DLL Wsa : Echec.\n"); } //Création de la Socket serveur : Protocole IPv4, Flux de données binaires, Protocole TCP ( mode "connecté") if((serveur.Sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { Fin("Echec lors de la création de la Socket serveur.\n"); } //Remplissage de la structure concernant les informations de la Socket serveur.Sin.sin_family = PF_INET; //Protocole IPv4 serveur.Sin.sin_addr.s_addr = htonl(INADDR_ANY); //Ecoute sur toutes les adresses IP serveur.Sin.sin_port = htons(PORTSQL); //Port du serveur //Liaison de la Socket serveur avec la structure Sockaddr //La structure contenant les informations est Sockaddr_in, nous faisons donc un cast if(bind(serveur.Sock, (SOCKADDR *)&serveur.Sin, sizeof(serveur.Sin)) == SOCKET_ERROR) { Fin("Echec du bind.\n"); } if(listen(serveur.Sock, 0) == SOCKET_ERROR) { Fin("Echec de l'écoute sur la Socket.\n"); } t_client clients[NBMAX]; fd_set readfds; //Descripteur : lecture max = serveur.Sock; actuel = 0; break; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Service RUN pour Serveur. case SERVEUR_RUN : for(;;) { FD_ZERO (&readfds); FD_SET(serveur.Sock, &readfds); for(i = 0; i <= actuel ; i++) { FD_SET(clients[i].Sock, &readfds); } if(select(0, &readfds, NULL, NULL, 0) == -1) { Fin("Erreur lors du select()."); } if(FD_ISSET(serveur.Sock, &readfds)) { serveur.Csock = accept(serveur.Sock, (SOCKADDR *)&(serveur.Csin), &(serveur.Sinsize)); if(pa == INVALID_SOCKET) { Fin("Echec de la connection du clients.\n"); } printf("\nNouvelle connexion : %s se connecte.\n", inet_ntoa(serveur.Csin.sin_addr)); strcpy(Buff, "-- Bienvenue sur le serveur SQL"); send(clients[i].Sock, Buff, (int)strlen(Buff), 0); max = serveur.Csock > max ? serveur.Csock : max; FD_SET(serveur.Csock, &readfds); t_client c = { serveur.Csock }; strncpy(c.pName, Buff, BUFF_SIZE - 1); clients[actuel] = c; actuel++; } else { for(i = 0; i <= actuel ; i++) { if(FD_ISSET(clients[i].Sock, &readfds)) { Serveur(SERVEUR_RECV, 0); Serveur(SERVEUR_SEND, 0); } } } } break; (...) } return 0; }
Non, un oublie de ma part, modifié à NBMAX ( = 10 ).
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager