Journal Broadcast en C

Posté par  .
Étiquettes : aucune
0
21
mar.
2004
Coucou c'est re-mouaaaaaa !

Bon, cette fois je fournis mon code source du serveur complet, pour que les puristes puissent faire "arrrghhhh", et que les autres puissent m'aider :-)

Alors déjà si quelqu'un a compris ce que je veux faire a la seule vue du code bravo !

Pour les autres, je tente une pseudo technique crado, pour tenter d'imiter une sorte de wall.
Le serveur ecoute sur un port, quand quelqu'un se pointe, il accepte la connexion. problème, j'arrive pas a le faire accepter sur un autre port que celui sur lequel il ecoute ! :-(

Résultat dès qu'un client se connecte, le serveur n'ecoute plus...

Si quelqu'un peut m'aider en pointant l'os dans le paté, ou meme en me corrigant 2-3 lignes de codes (pas tout hein, yaurai trop a faire pour que ce soit propre...puis jlaime bien mon style crados de pseudo codeur en herbe)

Bref,

merci d'avance.

P.S : oui je sais, le code est pourri, mal codé, et c'est débile de vouloir faire ca, mais si vous voulez pas m'aider, me criez pas dessus hein, allez donc lire un autre journal, yen a plein

- cho7, celui qui se fait souvent crié dessus, car il poste des journaux sans interet aucun, et qu'en plus il a pseudo totalement con -




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define MAX_CONNECT 50
#define PORT 1983

int main(int argc, char * argv[])
{
int i;
int nb_connect=0; /* nombre de connexions en cours*/
int fds,nb_octets;
int fdc[MAX_CONNECT]; /* table contenant tous les file descriptor des clients */
int sin_size;
struct sockaddr_in serveur; /* les sockets */
struct sockaddr_in client[MAX_CONNECT];
char message[256]; /* on y stock les datas émisent par les différents clients */

/* on ouvre un socket */
if ((fds=socket(AF_INET,SOCK_STREAM,0))==-1)
{
printf("Erreur, le socket serveur n'a pu etre créé !\n");
exit(1);
}

/* on initialise tout */
serveur.sin_family=AF_INET;
serveur.sin_port=htons(PORT);
serveur.sin_addr.s_addr=INADDR_ANY;
memset(&(serveur.sin_zero),'\0',8);

/* on bind le socket */
if (bind(fds,(struct sockaddr *)&serveur,sizeof(struct sockaddr)) == -1)
{
printf("Erreur, le bind n'a serveur n'a pu etre effectué !\n");
exit(1);
}

if (listen(fds,5) == -1)
{
printf("Erreur, la fonction listen coince !");
exit(1);
}


/* démarrage de la boucle evenementielle infinie */
while(1)
{
sin_size = sizeof(struct sockaddr_in);



if ((fdc[nb_connect]=accept(fds,(struct sockaddr *)&client[nb_connect],&sin_size)) == -1)
{

continue;
}
else
{
nb_connect++; /* hop, un client de plus */
}

for (i=0;i<nb_connect;i++)
{
/* on récupere pour chaque file descriptor les données qui veulent entrer sur le serveur */
if ((nb_octets=recv(fdc[i],message,256,0)) == -1)
{
message[nb_octets]='\0';
printf("%s\n",message);

}

}

for (i=0;i<nb_connect;i++)
{
/* on ferme tous les sockets client */
close(fdc[i]);
}
close(fds);
}

return 0;
}
  • # Re: Broadcast en C

    Posté par  . Évalué à 4.

    l'accept te fournit une nouvelle socket (partagé avec le client).
    Il faut alors forker (man fork)
    le pere retourne attandre sur l'accpet
    le fils discute avec le client..


    A+
    • [^] # Re: Broadcast en C

      Posté par  (site web personnel) . Évalué à 3.

      on peut au lieu de créer un nouveau process créer un nouveau thread traitant la com avec la nouvelle socket...
      • [^] # Re: Broadcast en C

        Posté par  . Évalué à 1.

        En effet, il serait plus évident d'utiliser les threads car d'après ce que j'ai compris ( qq bières dans la tête n'aidant pas), les connexions entrantes écrivent un truc dans un buffer.
        Sachant que pr accepter plusieurs connexions, tu dois créer un nouveau process qui pourra écrire dans cette variable il te faut un thread. En effet, un fork n'est rien d'autre qu'une copie mémoire du process s'executant. Toutes tes modifications au variables programme principal n'auront donc aucun effet pr les variables du programmes principal.
        Donc deux solutions:
        1/ Le thread (pthread_create())
        2/ Garder un process unique et x sockets (select())

        En espèrant avoir été suffisament compréhensible,

        ++, Gérald.
    • [^] # Re: Broadcast en C

      Posté par  . Évalué à 2.

      Ou faire ca avec des thread : soit tu crées un nouveau threads à chaque fois via pthread_create, tu lui passes bien sur en argument le socket lié à ta connection et il se débrouille. Soit t'as un pool de threads déja crées et tu dispatchs tes connections, t'en crées de nouveau dés que tu sens qu'ils vont tous être occupés, c'est plus compliqué mais nettement plus performant.
    • [^] # Re: Broadcast en C

      Posté par  . Évalué à 0.

      J'ai compris l'idée du fork, mais je sais pas l'implémenter dans mon code :-(

      Je débute en C, j'suis vraiment pas doué !
  • # Re: Broadcast en C

    Posté par  . Évalué à 3.

    un monsieur t'a dit d'essayer avec select (). C'est un peu plus compliqué, mais ça vaut le coup.
    • [^] # Re: Broadcast en C

      Posté par  . Évalué à 1.

      mais meme avec la page de man, je pige pas comment ca marche ! :-(

      C'est pour ca que jvoulais tenter de faire accepter la connexion sur un nouveau port, quitte a en monopoliser 1000 si ya 1000 clients, car je pense que ce serait plus simple pour moi.
      • [^] # Re: Broadcast en C

        Posté par  (site web personnel) . Évalué à 1.

        De toutes facons, tu auras toujours 1000 sockets à gérer.

        Donc il faudra soit créer 1000 threads, chacun gérant une socket, soit faire un select.

        Grosso modo, select, c'est, tu mets tous tes descripteurs de socket ( l'entier renvoyé par accept) dans un fd_set tu fais un select en spécifiant un timeout, et il te renvoie le fd_set avec dedans toutes les sockets sur lesquelles quelque chose est arrivé (c'est très simplifié comme explication)

        Donc, grosso modo, en mettant que tu aies un tableau sockets contenant les descripteurs, et fd l'identifiant de ton fd_set:

        fd_set fd;
        struct timeval timeout;

        /* On vide le fd_set
        FD_ZERO( &fd );

        /* On remplit le fd_set */
        for( i = 0 ; i< taille_de_sockets ; i++)
        {
        FD_SET( sockets[i]; &fd );
        }

        /* Attendre 1seconde et demi */
        timeout.tv_sec = 1;
        timeout.tv_sec = 500000;

        i_ret = select( taille_de_sockets, &fd, NULL, NULL, &timeout);

        /* On regarde quelles sockets ont répondu et on traite */
        if( i_ret == -1 && errno != EINTR)
        {
        /* Erreur */
        }
        else if (i_ret > 0)
        {
        /* Au moins une socket a renvoyé qqch (le nombre de sockets ayant renvoyé est i_ret) */

        for (i = 0 ; i< taille_de_sockets ; i++)
        {
        if( FD_ISSET( sockets[i], &fd ) )
        {
        /* Des données sont arrivées sur cette socket */
        process( sockets[i] );
        /* On peut faire un recv sur cette socket pour récupérer les données*/
        }
        }
        }
        else if( i_ret == 0)
        {
        /* Aucune socket n'a recu de données avant l'expiration du timeout */
        }
        • [^] # Re: Broadcast en C

          Posté par  . Évalué à 0.

          J'ai tenté d'integrer ton truc dedans, mais ca coince, le serveur réagit pas : jette donc un oeil


          #include <stdio.h>
          #include <stdlib.h>
          #include <string.h>
          #include <sys/types.h>
          #include <sys/socket.h>
          #include <netinet/in.h>
          #include <sys/time.h>
          #define MAX_CONNECT 50
          #define PORT 1983

          int main(int argc, char * argv[])
          {
          int i;
          int ret_val;
          int nb_connect=0; /* nombre de connexions en cours*/
          int nb_octets;
          int fds; /* table contenant tous les file descriptor des clients */
          int fdc[MAX_CONNECT];
          int sin_size;
          struct sockaddr_in serveur; /* les sockets */
          struct sockaddr_in client;
          fd_set fd;
          struct timeval timeout;

          char message[256]; /* on y stock les datas émisent par les différents clients */

          /* on ouvre un socket */
          if ((fds=socket(AF_INET,SOCK_STREAM,0))==-1)
          {
          printf("Erreur, le socket serveur n'a pu etre créé !\n");
          exit(1);
          }

          /* on initialise tout */
          serveur.sin_family=AF_INET;
          serveur.sin_port=htons(PORT);
          serveur.sin_addr.s_addr=INADDR_ANY;
          memset(&(serveur.sin_zero),'\0',8);

          /* on bind le socket */
          if (bind(fds,(struct sockaddr *)&serveur,sizeof(struct sockaddr)) == -1)
          {
          printf("Erreur, le bind serveur n'a pu etre effectué !\n");
          exit(1);
          }

          if (listen(fds,5) == -1)
          {
          printf("Erreur, la fonction listen coince !");
          exit(1);
          }


          /* démarrage de la boucle evenementielle infinie */
          while(1)
          {
          sin_size = sizeof(struct sockaddr_in);
          timeout.tv_sec=1; /* rafraichissement du select = 1 seconde */





          if ((fdc[nb_connect]=accept(fds,(struct sockaddr *)&client,&sin_size)) == -1)
          {

          continue;
          }
          else
          {
          printf("Connexion d'un nouveau client (file descriptor : %d) sur le port %d\n",fdc[nb_connect],(int)client.sin_port);
          FD_SET(fdc[nb_connect],&fd); /* on ajoute le fd dans le select */
          nb_connect++;

          }




          ret_val=select(nb_connect,&fd,NULL,NULL,&timeout);

          if (ret_val>0) /* des données sont arrivées via un des sockets */
          {

          for (i=0;i<nb_connect;i++)
          {
          if(FD_ISSET(fdc[i],&fd))
          {


          /* on récupere pour chaque file descriptor les données qui veulent entrer sur le serveur */
          if ((nb_octets=recv(fdc[i],message,256,0)) == -1)
          {
          message[nb_octets]='\0';
          printf("%s\n",message);

          }
          } /* fin du FD_ISSET*/
          } /* fin du for*/

          }/* fin ret_val */

          }
          for (i=0;i<nb_connect;i++)
          close(fdc[i]);

          close(fds);

          return 0;
          }
          • [^] # Re: Broadcast en C

            Posté par  (site web personnel) . Évalué à 1.

            Normal, l'appel à accept est bloquant, il attend vraiment une connection.

            Ce que tu dois faire: dans le FD_SET, tu mets tous tes fdc et le fds.

            Quand tu recois des données sur fds, alors tu fais un accept sur le fds pour récupérer le nouveau fdc et l'appel à acccept retournera tout de suite
  • # Re: Broadcast en C

    Posté par  . Évalué à 1.

    "Le serveur ecoute sur un port, quand quelqu'un se pointe, il accepte la connexion. problème, j'arrive pas a le faire accepter sur un autre port que celui sur lequel il ecoute ! :-("

    Gnnnnn ? C'est quoi cette idée de ouf ?
    • [^] # Re: Broadcast en C

      Posté par  . Évalué à 4.

      C'est une idée que la pluspart ds gens qui code avec les socket ne comprenent pas.
      alors soit gentil avec lui.

      T'a plein de gens qui discute en même temps sur le port 80 d'un serveur web.
      Comment le systéme fait pour retrouver le bon process a qui envoyer les données?
      Il utilise le port src.

      Donc en fait ca phrase est plutot : j'arrive pas a le accepter depuis un autre port source !
    • [^] # Re: Broadcast en C

      Posté par  . Évalué à 1.

      Bah perso moi dans d'autres langages comme VB ou delphi, on peut ecouter sur un port, et accepter la connexion sur un autre.
      Comme ca le port initial reste libre d'ecouter les nouvelles demandes de connexions.

      en gros :

      serveur : listening on port 1983...
      client : request_connection on port 1983
      serveur : accept_connection on port 0 (=1er port disponible)
      client : connecting to port 0 (le port attribué précédemment)
      serveur : listening on port 1983...
      etc...

      C'etait comme ca que le chat que j'avais fais en bts fonctionnait.

      Car si je faisai un winsock.accept directement sur le port 1983, bah la connexion se faisait, mais les autres clients ne peuvent plus se connecter, car le port 1983 du serveur etait occupé !


      Bref, j'ai ptetre rien compris, mais moi c'est le seul moyen que j'avais trouvé pour que ca marche.
      • [^] # Re: Broadcast en C

        Posté par  (site web personnel) . Évalué à 1.

        mwai, enfin bon, si avec 1000 clients tu dois monopoliser 1000 ports :) c'est pas génial :)

        La solution la meilleur est accept().

        Meme si le concept est un peu dure a comprendre au premier abord, ca marche tres bien :)
      • [^] # Re: Broadcast en C

        Posté par  . Évalué à 1.

        Je comprends mieux tes motivations, mais en fait en C c'est bien plus compliqué (je ne sais meme pas si c'est possible) de faire ca que d'avoir un comportement "à la serveur web", c'est à dire un unique port coté serveur, et n'importe quel port coté client. Tu peux avoir plusieurs connexion simultanées sur un même port, car port != socket. Au niveau du protocole tcp / ip, les paquet sont triés par rapport à l'ip et au port source.
      • [^] # Re: Broadcast en C

        Posté par  . Évalué à 1.

        > Bah perso moi dans d'autres langages comme VB ou delphi, on peut ecouter sur un port, et accepter la connexion sur un autre.
        > Comme ca le port initial reste libre d'ecouter les nouvelles demandes de connexions.


        Heeeuuuurrrkkkkk.... Le problème avec les programes comme celui que tu as developpé, c'est que tu ammenes ca dans une boite, on l'installe, et apres l'utilisateur va voir l'administrateur reseau/securité pour lui demander d'ouvrir des ports.

        L'admin, generalement assez sympa, il demande (juste comme ça, en passant) : "Bon, il faut que je t'ouvre quels ports ? TCP/UDP ? vers où ? Y a un créneau horaire ?" (Oui, un admin c'est generalement assez parano...)
        Et l'utilisateur du sus-dit logiciel qui répond, l'air de rien : "Bah en fait, il faudrait que tu m'ouvres tous les ports TCP > 1024, je ne sais quel port va utiliser mon serveur, c'est à la gueule du client..."

        Et bein, moi, je t'assure que si c'est moi l'admin, ton programme, tu peux en changer tout de suite, sans passer par la case lecteur de CD-ROM...
  • # Re: Broadcast en C

    Posté par  . Évalué à 2.

    Sacré coincidence, un mec a parlé du même sujet sur un autre journal, aujourd'hui même :

    http://linuxfr.org/~cho7kipu/10717.html(...)

    M
    • [^] # Re: Broadcast en C

      Posté par  . Évalué à 0.

      hum... ben le mec, c'est lui, en fait !
      • [^] # Re: Broadcast en C

        Posté par  . Évalué à 0.

        euh, j'suis pas sur, mais je crois que c'etait une critique, et non une phrase d'etonnement jovial :-)

        Ironie, quand tu nous tiens..
  • # Re: Broadcast en C

    Posté par  . Évalué à 1.

    C'est bon ca marche comme je veux !!

    Après plusieurs heures acharnées, jpense avoir enfin compris le principe, j'ai utilisé select()

    Merci a tous pour votre aide !

    merci, merci, et merci !
    • [^] # Re: Broadcast en C

      Posté par  . Évalué à 1.

      Tant quà faire comme tu débutes en C peut-être pourrais-tu prendre de bonnes habitudes dès le départ pour écrire un code propre (indentations, etc ...). Il est plus facile de prendre rapidement de bonnes habitudes que d'en perdre des mauvaises ....
  • # Commentaire supprimé

    Posté par  . Évalué à 1.

    Ce commentaire a été supprimé par l’équipe de modération.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.