Fonction accepte bloquante..

ssmint Messages postés 43 Date d'inscription mercredi 30 novembre 2005 Statut Membre Dernière intervention 5 décembre 2008 - 9 août 2006 à 23:46
ZapaN28 Messages postés 1 Date d'inscription mercredi 8 février 2006 Statut Membre Dernière intervention 9 septembre 2010 - 9 sept. 2010 à 15:05
Bonjour à tous,
nouveau problème de socket, côté server cette fois ci :
imaginons que plusieurs clients cherchent à se connecter sur le port d'écoute du server en même temps, 
je voudrais pouvoir recevoir toutes les connections puis choisir celle avec laquelle dialoguer...

=>Je fais donc un tableau de sock[] avec une boucle stoquant dans chaque sock les infos necessaires grâce à la fonction accept(), le problème, c'est que le socket server étant bloquant par défaut, la fonction accept() aussi..
Ce qui fait que la boucle bloque si il n'y a pas assez de conection entrantes. Dans mon code, j'ai pris 5 connections max mais s'il n'y en a que 2 ça ne marchepas , la boucle bloque sur la fonction accept()!!

=> Du coup, pas de problème : je rend donc le socket non bloquant grâce à la fonction ioctlsocket()!!

=> Sauf que du coup j'ai un autre problème lors de la communication avec le client, la fonction recv() n'est pas bloquante!
Alors c'est franchement chiant pour dialoguer, il faut mettre la fonction recv() dans une boucle infini pour recevoir un truc, compte tenu ds fonctionnalités que je veux mettre dans le prog, c'est impossible...

J'aimerais donc savoir si c'est possible de mettre une sorte de timeout sur la fonction accept() avec un socket bloquant ou "rerendre" le socket bloquant après avoir choisi le client (se que j'ai essayé mais qui ne marche pas)...

Voici mon code :

#include <stdio.h>
#include <winsock2.h>
#include <string.h>





int main()
{
// variables   
WSADATA wsa;
SOCKET server;    //Le socket qui servira à écouter sur un port
SOCKET sock[5];   //les sockets qui serviront à communiquer
SOCKADDR_IN sinserv; //parametres pour server
SOCKADDR_IN sin[5];  //parametres pour socks



char buffer[50], *P, *ip;
int sinsize;
int i=0, c,tmp;





     // Présentation :
                   
    system("color a");
    system("cls");
    system("TITLE TCP server by ssmint");



    // Mise en place de l'écoute : 
    
 WSAStartup(MAKEWORD(2,2),&wsa);
      
 sinserv.sin_family = AF_INET;         
 sinserv.sin_addr.s_addr = INADDR_ANY;    
 sinserv.sin_port=htons(1234);



 server = socket(AF_INET,SOCK_STREAM,0);
 bind(server,(SOCKADDR*)&sinserv,sizeof(sinserv));



 listen(server,5);
   
    // Socket rendu non bloquant : 
              
    u_long p=1;
    ioctlsocket(server, FIONBIO,&p);



    // Affichage connections et choix :
   
    printf("\nEcoute sur le port 1234. ..\t (3 sec)\n\n");
    Sleep(3000);//necessaire pour mettre connection en queue
    printf("Connexions recues :\t(5 max)\n");
    memset(buffer,sizeof(buffer),0);
    
    sinsize=sizeof(sin);
    while((sock[i]=accept(server,(SOCKADDR*)&sin[i],&sinsize))!=INVALID_SOCKET)
    {
           
            ip = inet_ntoa(sin[i].sin_addr);   //affichage ip client...
            printf("\n [%d]  %s ",i+1,ip);
            i++;
            
    }
        
      // Pas de connections :
              
        if(sock[0]==INVALID_SOCKET)
        {
              printf("\n\tAucune\n\n");
              system("pause");
              WSACleanup();
              exit(0);
        }
       
        // Choix de la connection pour dialogue :
                
        printf("\n=> Selection connection: ");
        scanf("%d", &c);
        c--;
       
        // Fermeture des sockets inutilisés :
                    
        for(i=0; i<5; i++)
        {
                 if(i!=c)
                 {
                            closesocket(sock[i]);
                 }
        }



        p=0;                                 // NE FONCTIONNE PAS!!!
        ioctlsocket(server, FIONBIO,&p);     //une fois la fonction accept() passé
                                             //le socket server reste non-bloquant
system("pause");
}


Merci d'avance désolé pour le "pavé".


 

3 réponses

nightlord666 Messages postés 746 Date d'inscription vendredi 17 juin 2005 Statut Membre Dernière intervention 23 mai 2007 10
10 août 2006 à 06:41
Pour ça, tu met ta boucle infinie avec recv dans un thread que tu aura créé. Regarde sur developpez.com, il y a un article sur les serveurs multithreads.

Sachant qu'on peut toujours enlever une ligne à un programme, et que dans un programme il y a toujours un bug, un programme peut se résumer à une ligne avec un bug.
0
turnerom Messages postés 492 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 12 janvier 2012 1
10 août 2006 à 09:52
Re,
il faut que tu utilise la fonction select, voici un exemple de code qui marche (version Linux par contre mais l'idée est la, c'est + ou - la meme chose sous WinWin)
Ce code permet a nombre illimité (enfin presque 64511 pour etre precis) de client de se connecter, et lui envoi le fichier passer en paramètre.

int
main
(
int
argc, char*argv[])
{

intds,port,ta,da,sock;
structsockaddr_inname;

if(argc!= 2)/* Test Le nombre d'arguments */
{
fprintf(stderr,"Usage : ./serveur port \n");
exit(0);
}

puts("Serveur en attente");/*Message d'attente*/
puts("");

port =atoi(argv[1]);/*L'argument 1 est le numero de port sur lequel le serveur attend*/

ds= socket(PF_INET, SOCK_STREAM, 0);/*On crée notre socket de connection*/

if (ds<0)/*Avec un test pour éviter les erreurs*/
{
perror("Probleme socket : ");
exit(-1);
}

init_sockaddr(&name,"0.0.0.0",port);/*On initialise notre socket internet, le port ecoute sur toute les adresse*/

if(bind(ds, (structsockaddr*)&name, sizeof(structsockaddr))<0)/*On bind*/
{/*Avec un test pour éviter les erreurs*/
perror("Probleme bind : ");
exit(-1);
}

if(listen(ds, FILED)<0)/*On listen dans notre socket de connexion jusqu'à "FILED" client max*/
{/*Avec un test pour éviter les erreurs*/
perror("Probleme listen ");
exit(-2);
}

while(1)/*Serveur multi-client donc boucle infinie*/
{

FD_ZERO(listeClients);/*On reinitialise notre liste d'attente*/
FD_SET(ds,listeClients);/*Dans laquelle on place notre socket de connexion*/

if((select(FILED+1, listeClients, NULL, NULL,NULL))<0)/*On fait notre select sur notre liste de client*/
{/*Avec un test pour éviter les erreurs*/
perror("select");
exit(-3);
}

for(sock =3;sock<FILED;sock++)/*On parcourt toutes nos (potentielles) sockets*/
{

if(FD_ISSET(sock,listeClients))/*On regarde quelle descripteur change d'etat*/
{
if(sock= =ds)/*Si c'est la socket de connection...*/
{
da =accept(ds, (structsockaddr*)&name, &ta);/*...on l'accepte...*/
if(da<0)/*...toujours avec un test pour éviter les erreurs...*/
{
perror("Probleme accept ");
exit(-3);
}
printf("Connexion socket n°%d établie\n",da);
FD_SET(da,listeClients);/*...et on la rajoute dans notre liste de clients*/
}
elsetraiterClient(sock);/*Si ce n'est pas la socket de connection, c'est alors une socket de data*/
/*On appelle donc notre fonction de transfert proprement dite en passant en argument...*/
}/*...la socket où le client envoi son fichier*/
}

}

close(da);
close(ds);

return0;
}

voidinit_sockaddr(structsockaddr_in*name, constchar*hostname, uint16_tport)
{
structhostent*hostinfo;

name->sin_family= AF_INET;/* Adresses IPV4 (Internet) */
name->sin_port=htons(port);/* On gère le little/big Endian */

hostinfo=gethostbyname(hostname);/* appeler les fonctions de résolution de nom de la libC */

if (hostinfo == NULL)/* Si ne peut transformer le nom de la machine en adresse IP */
{
fprintf(stderr, "Unknown host %s.\n", hostname);
exit(-1);
}
name->sin_addr =*(structin_addr*)hostinfo->h_addr;/* Le dernier champs de la structure est garni */
}

voidtraiterClient(intda)
{
charbuffer[SIZE],nomFich[SIZE];
intfich;
ssize_tsize;

if(read(da,nomFich,SIZE)<0)/*On récupere le nom du fichier*/
{/*Avec toujours un petit test pour éviter les erreurs*/
perror("Nom de fichier non recu : ");
exit(-4);
}

if(nomFich= =NULL)/*Avec meme un 2eme test pour être totalement sûr*/
{
perror("Nom de fichier invalide");
exit(-5);
}

/*Si tout es bon...*/
fich =open(nomFich,O_WRONLY|O_CREAT,777/*,S_IRWXU|S_IRWXG|S_IRWXO*/);/*On ouvre le fichier (ou on le cree s'il n'existe pas) en lecture seule avec le nom recu*/
/* voir (1) en bas de page*/
puts("Réception en cours...");

while((size=read(da,buffer,SIZE)))write(fich,buffer,size);/*Tant que c'est pas la fin du fichier on lit dans la socket et on ecrit dans le fichier*/

puts("Réception terminée");
puts("");

close(da);/*On ferme la socket...*/
close(fich);/*...et le fichier*/

}





TuRn3r
0
ZapaN28 Messages postés 1 Date d'inscription mercredi 8 février 2006 Statut Membre Dernière intervention 9 septembre 2010
9 sept. 2010 à 15:05
ssmint a dit :
"je rend donc le socket non bloquant grâce à la fonction ioctlsocket()!"

merci je connaissais pas ! ca va m'aider nikel

Zap ;)
0
Rejoignez-nous