Linux, C & Sockets

Signaler
Messages postés
10
Date d'inscription
dimanche 5 septembre 2004
Statut
Membre
Dernière intervention
29 octobre 2004
-
Messages postés
10
Date d'inscription
dimanche 5 septembre 2004
Statut
Membre
Dernière intervention
29 octobre 2004
-
Bonjour!

Je pense devenir fou...
Je programme actuellement une architecture serveur/client en C.
Le problème est que pour tous les clients qui se connectent au serveur, l'appel:
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
me retourne toujours 0.
Evidement, l'appel:
FILE *fdopen(int fildes, const char *mode);
me retourne alors une erreur.

Si quelqu'un à une idée ce serait très gentil de m'éclairer...

Merci,
Christophe

PS: Je peux envoyer le code source (ipc_socket.c) directement compilable et exécutable (gcc -Wall -o ipc_socket ipc_socket.c) sous Linux.

5 réponses

Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
salut,
copie colle ici ton code, sinon ca sera difficile de t'aider...
a+ ;)
Messages postés
10
Date d'inscription
dimanche 5 septembre 2004
Statut
Membre
Dernière intervention
29 octobre 2004

Merci de ta proposition!

Toutefois, mon code fonctionne enfin!
Le problème venait du fait que l'allocation mémoire se faisait dans un processus fils, et apparement cela déplaisait pas mal à gcc...
Finalement, comme je connaissais la quantité de mémoire nécessaire, j'ai fait le "malloc" avant le "fork".
Et là, STUPEUR: tout fonctionne!

Malgré tout, une question me taraude...
Dans une architecture client/serveur: est préférable d'avoir:
- un processus pour le serveur et un processus pour tous les clients,
ou
- un processus pour le serveur et un processus pour chaque client?

Ceci sachant que les clients n'ont nul besoin de communiquer directement entre eux sans passer par le serveur.

Si vous avez des arguments pour l'une ou l'autre des solutions, je suis preneur!

Merci!
Christophe

PS: si certains en ont besoin, je peux poster mon code commenté (sockets, processus...) pour les aider à apprendre les communications inter-processus (ipc).
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
tout dépend des circonstances, mais d'un point de vue de memoire, les threads sont beaucoup plus avantageux que les processus (thread = processus light, dit on).
en plus, si les différents threads du processus client n'ont pas besoin de communiquer entre eux, pas besoin de synchronisation, dc c'est a priori aussi simple (du point de vue code) que d'avoir plusieurs processus.
le truc est de savoir a quel moment un nouveau client apparait (soit c automatique, soit c'est un utilisateur physique qui en a besoin). si un nouveau client est necessaire pour chaque personne physique, mieux vaut ss doute plusieurs processus... car sinon tu dois expliquer a un processus qui existe deja qu'il doit lancer un nouvau thread.
enfin bref, comme d'hab, ca dépend ;)

a++
Messages postés
10
Date d'inscription
dimanche 5 septembre 2004
Statut
Membre
Dernière intervention
29 octobre 2004

Bonsoir!

Oui, c'est vrai avec des threads se sera déjà plus léger.
Disons, que le serveur attend un nombre prédéterminé de clients. Une fois tous les clients connectés, le serveur joue le rôle de médiateurs entre les clients, c'est à dire que: il redistribue les informations de certains clients à d'autres clients qui ont besoin de ces informations.
Je pense alors qu'un processus par client sera plus propre, mais cela va être assez tendu à coder.
Je te tiens au courrant, tu trouveras le code pour un processus serveur et un processus clients, si cela t'intéresse. Pour l'instant, le serveur ne fait qu'envoyer une phrase aux clients et ceux-ci l'affichent à l'écran.

/* fichier: ipc_socket.c
 * créé le: 29/09/2004
 * dernière modification le: 30/09/2004
 * auteur: christophe bismuth
 * sujet : communication inter-processus par sockets (SOCK_STREAM)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include 
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>

#define NCLIENTS 5 /* nombre de client(s) attendu(s) sur le serveur */
#define NATTEMPTS 100000 /* nombre de tentative(s) de connection(s) sur le serveur (pour chaque client) */

int createUNIXStreamSocketServer(int *st, char *address, int fs[NCLIENTS]) {

  int from_length;
  register int length;
  register int accepted = 0;
  struct sockaddr_un saun;

  /* creation de la socket */
  if ((*st = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    fprintf(stderr, "createUNIXStreamSocketServer: socket() failed\n");
    return(1);
  } else fprintf(stderr, "createUNIXStreamSocketServer: socket created in AF_UNIX domain\n");

  /* assignation du domaine de communication */
  saun.sun_family = AF_UNIX;

  /* assignation de l'adresse de connexion */
  if (strcpy(saun.sun_path, address) == NULL) {
    fprintf(stderr, "createUNIXStreamSocketServer: strcpy() failed\n");
    close(*st);
    return(1);
  } else fprintf(stderr, "createUNIXStreamSocketServer: socket address loaded\n");

  /* liberation de l'adresse de connexion */
  unlink(address);

  length = sizeof(saun.sun_family) + strlen(saun.sun_path);

  /* lien entre la socket et l'adresse de connexion */
  if (bind(*st, (struct sockaddr *) &saun, length) < 0) {
    fprintf(stderr, "createUNIXStreamSocketServer: bind() failed\n");
    close(*st);
    return(1);
  } else fprintf(stderr, "createUNIXStreamSocketServer: socket named in file system\n");

  /* ecoute du serveur de 'backlog' client(s) */
  if (listen(*st, NCLIENTS) < 0) {
    fprintf(stderr, "createUNIXStreamSocketServer: listen() failed\n");
    close(*st);
    return(1);
  } else fprintf(stderr, "createUNIXStreamSocketServer: %d connection request(s) can be queued\n", NCLIENTS);

  /* attente des 'backlog' client(s) */
  fprintf(stderr, "createUNIXStreamSocketServer: waiting for %d client(s) to connect...\n", NCLIENTS);
  while(1) {
    if ((fs[accepted] = accept(*st, (struct sockaddr *) &saun, &from_length)) < 0) {
      fprintf(stderr, "createUNIXStreamSocketServer: accept() failed for client %d\n", accepted);
      close(*st);
      return(1);
    }
    else {
      accepted = accepted + 1;
      fprintf(stderr, "createUNIXStreamSocketServer: %d client(s) accepted\n", accepted);
      if (accepted == NCLIENTS) break;
    }
  }

  return(0);

}

int connectUNIXStreamSocketClient(int *st, char *address) {

  register int length;
  register int attempts = 0;
  struct sockaddr_un saun;

  /* creation de la socket */
  if ((*st = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    fprintf(stderr, "connectUNIXStreamSocketClient: socket() failed\n");
    return(1);
  } else fprintf(stderr, "connectUNIXStreamSocketClient: socket created in AF_UNIX domain\n");

  /* assignation du domaine de communication */
  saun.sun_family = AF_UNIX;

  /* assignation de l'adresse de connexion */
  if (strcpy(saun.sun_path, address) == NULL) {
    fprintf(stderr, "connectUNIXStreamSocketClient: strcpy() failed\n");
    close(*st);
    return(1);
  } else fprintf(stderr, "connectUNIXStreamSocketClient: socket address loaded\n");

  length = sizeof(saun.sun_family) + strlen(saun.sun_path);

  /* tentative(s) de connexion au serveur */
  while (attempts < NATTEMPTS) {
    if (connect(*st, (struct sockaddr *) &saun, length) < 0) attempts++;
    else break;
  }
  if (attempts == NATTEMPTS) {
    fprintf(stderr, "connectUNIXStreamSocketClient: connect() failed\n");
    close(*st);
    return(1);
  } else fprintf(stderr, "connectUNIXStreamSocketClient: client connected\n");

  return(0);

}

int main(void) {

  char c;
  register int i, j;
  char *address = "stream";
  int server_socket;
  int client_socket[NCLIENTS];
  int fs[NCLIENTS];
  FILE **fp_server = NULL;
  FILE **fp_client = NULL;

  /* allocation memoire de la table de descripteur(s) de ficher(s) du(des) socket(s) acceptee(s) par le serveur */  if (((fp_server) (FILE **) malloc(sizeof(FILE *) * NCLIENTS)) NULL) {
    fprintf(stderr, "main: malloc() failed for server\n");
    exit(1);
  } else fprintf(stderr, "main: file descriptor(s) for server loaded in memory\n");

  /* allocation memoire de la table de descripteur(s) de ficher(s) du(des) socket(s) connectee(s) au serveur */  if ((fp_client (FILE **) malloc(sizeof(FILE *) * NCLIENTS)) NULL) {
    fprintf(stderr, "main: malloc() failed for client(s)\n");
    exit(1);
  } else fprintf(stderr, "main: file descriptor(s) for client(s) loaded in memory\n");

  switch(fork()) {

    case -1: fprintf(stderr, "main: fork() failed\n"); exit(1);

    case 0: /* processus fils: connexion(s) du(des) client(s) au serveur */

      /* connexion(s) des NCLIENTS au serveur */
      for (i = 0; i < NCLIENTS; i++) {
        if (connectUNIXStreamSocketClient(&client_socket[i], address) != 0) {
          for (j = 0; j < i; j++) close(client_socket[j]);
          exit(1);
        }
      }

      /* association(s) flux/descripteur(s) de fichier(s) */
      for (i = 0; i < NCLIENTS; i++) {
        if ((fp_client[i] = fdopen(client_socket[i], "r")) == NULL) {
          fprintf(stderr, "main: fdopen() failed for client %d\n", i);
          for(j = 0; j < NCLIENTS; j++) close(client_socket[j]);
          exit(1);
        } else fprintf(stderr, "main: client %d stream associated with file descriptor\n", i);
      }

      /* lecture(s) du(des) message(s) envoye(s) par le serveur */
      for (i = 0; i < NCLIENTS; i++) {
        while((c = fgetc(fp_client[i])) != EOF) {
          putchar(c);
          if (c == '\n') break;
        } fprintf(stderr, "main: end of server message transmission by client %i\n", i);
      }
      fprintf(stderr, "main: end of client process\n");

      break;

    default: /* processus pere: creation du serveur */

      /* creation du serveur */
      if (createUNIXStreamSocketServer(&server_socket, address, fs) != 0) exit(1);

      /* association(s) descripteur(s) de socket(s)/descripteur(s) de fichier(s) */
      for (i = 0; i < NCLIENTS; i++) {
        if ((fp_server[i] = fdopen(fs[i], "r")) == NULL) {
          fprintf(stderr, "main: fdopen() failed for server and client %d\n", i);
          close(server_socket);
    wait(0);
          exit(1);
        } else fprintf(stderr, "main: server stream associated with file descriptor of client %d\n", i);
      }

      /* envoi(s) du(des) message(s) au(x) client(s) */
      for (i = 0; i < NCLIENTS; i++) {
        if (send(fs[i], "server message\n", strlen("server message\n"), 0) < 0) {
          fprintf(stderr, "main: send() failed for client %d\n", i);
          close(server_socket);
    wait(0);
          exit(1);
        } else fprintf(stderr, "main: message sent to client %d\n", i);
      }
      fprintf(stderr, "main: end of server process\n");
      wait(0);
      break;

  }

  /* fermetures des sockets serveur et cliente(s) */
  close(server_socket);
  for(j = 0; j < NCLIENTS; j++) close(client_socket[j]);

  exit(0);

}


Merci!
@+

Christophe
Messages postés
10
Date d'inscription
dimanche 5 septembre 2004
Statut
Membre
Dernière intervention
29 octobre 2004

Les indentations, même avec des espaces en début de ligne ne passent pô... C'est pas très lisible comme ça, dommage...

Christophe