Accept: socket operation on non-socket

Voir le sujet précédent Voir le sujet suivant Aller en bas

Accept: socket operation on non-socket

Message  Mr_belette le Dim 12 Juil 2009 - 21:54

Bonjour,

Contexte :
Dans un but éducatif, je tente de développer une petite application console (sous linux) permettant d'envoyer des fichiers par le réseau internet.

Problème:
Du côté serveur de l'application. Je souhaite que mon programme permette à l'utilisateur d' entrer des commandes sans interruption, même pendant l'appel à une fonction accept(). J'ai donc décidé de lancer la fonction accept() dans un thread, en envoyant également au thread les informations nécessaires à la fonction. Extrait :

Code:
typedef struct {

    int sock;          // socket serveur
    int *csock;        // tableau de sockets client
    struct sockaddr_in csin;
    unsigned int crecsize;

} S_socket;

static void*
server_first_thread(void *data)
{
    int free_number = 0;                // pour trouver un socket libre dans le tableau de sockets clients
    S_socket *socket_data = (S_socket *) data;  // pour récuprer notre structure passée en argument
    unsigned int crecsize = (unsigned int) sizeof socket_data->csin; 

    while (1) {

    free_number = find_unused_socket_number(socket_data->csock);

    /* si on ne trouve pas de socket libre */
    if (free_number == -1) {
        pthread_exit(NULL);
    }

    /* ACCEPT ----------------- */
    socket_data->csock[free_number] = accept(socket_data->sock,
        (struct sockaddr *) &socket_data->csin,
        &crecsize);

        if (socket_data->csock[free_number] != INVALID_SOCKET) {

            printf(" -->One client connected from %s\n",
                inet_ntoa(socket_data->csin.sin_addr) );
        }
        else {
            perror ("accept");
            break;
        }
    }

 return (void *) NULL;
}

Cependant, lors du lancement du programme, après avoir lancé le serveur ( taper "start server" ), la fonction accept() renvoie une erreur que je n'arrive pas à comprendre.

J'ai googlisé un long moment en vain, j'ai cogité longtemps an vain également, j'ai vérifié les retours des fonctions socket(), listen(), bind() ... je ne sais plus quoi faire.

J'ai pensé finallement qu'il fallait initialiser les structures SOCKADDR_IN sin et csin, mais sous linux, la syntaxe trouvée sur ce site ne semble pas acceptée (ou alors par le compilateur), à savoir :
struct sockaddr_in machin = {0}; // renvoie une erreur de compilation

Veuillez trouver ci-dessous mon code complet en un fichier :
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>


#define INVALID_SOCKET  -1
#define SOCKET_ERROR    -1

#define PORT            6000
#define MAX_CONNEC      5


enum {EXIT, HELP, CONNECT, START_SERVER, START_CLIENT};


typedef struct {

    int sock;
    int *csock;
    struct sockaddr_in csin;
    unsigned int crecsize;

} S_socket;


void
clean_buffer (char *chaine) {

    char *p = strchr(chaine, '\n');
    int c;

    if (p) {
        *p = 0;
    }

    else  {
        while ((c = getchar()) != '\n' && c != EOF) {}
    }
}



int
client_start (const char **commands) {

    char chaine[32] = {0}; // stores user's commands
    int my_error = 0;

    while (1) {

        printf("client >");

        fgets(chaine, sizeof(chaine), stdin);
        clean_buffer(chaine);

        if (my_error != 0) {
            break;
        }
        else if ( strcmp(chaine, commands[EXIT]) == 0 ) {
            break;
        }
        else if (strcmp(chaine, commands[CONNECT]) == 0) {
            puts(" Starting client");
            //error = ;
        }
        else if (strcmp(chaine, commands[HELP]) == 0) {
            puts(" Available commands : \n exit\n connect");
        }
    }

    return my_error;
}

/* returns a freed place number from a socket(int) array */
int
find_unused_socket_number(int *array) {

  int retval = -1;

    for(int i = 0; i<7; i++) {
        if(array[i] == 0) {
            retval = i;
            break;
        }
    }

 return retval;
}


static void*
server_first_thread(void *data)
{
    int free_number = 0;
    S_socket *socket_data = (S_socket *) data;
    unsigned int crecsize = (unsigned int) sizeof socket_data->csin;

    while (1) {

    free_number = find_unused_socket_number(socket_data->csock);

    if (free_number == -1) {
        pthread_exit(NULL);
    }

    /* ACCEPT ----------------- */
    socket_data->csock[free_number] = accept(socket_data->sock,
        (struct sockaddr *) &socket_data->csin,
        &crecsize);

        if (socket_data->csock[free_number] != INVALID_SOCKET) {

            printf(" -->One client connected from %s\n",
                inet_ntoa(socket_data->csin.sin_addr) );
        }
        else {
            perror ("accept");
            break;
        }
    }

 return (void *) NULL;
}


int
server_start (const char **commands) {

    char chaine[32] = {0}; // stores user's commands
    int my_error = 0;

    //char *buffer = "bonjour";

    pthread_t t1;

    /* server side */
    struct sockaddr_in sin;
    int sock = 0;
    unsigned int recsize = (unsigned int) sizeof sin;

    /* client side */
    struct sockaddr_in csin;
    int csock[7] = {0};
//    unsigned int crecsize = (unsigned int) sizeof csin;

    S_socket send_to_thread = {
      .sock = sock,
      .csock = csock,
      .csin = csin
    };

    int sock_err;

    sock = socket(AF_INET, SOCK_STREAM, 0);

    if( sock >= 0 )
        {
            printf(" -->Socket %d is now opened in TCP/IP mode\n", sock);

            sin.sin_addr.s_addr = inet_addr("127.0.0.1");  /* htonl(INADDR_ANY); OR inet_addr("127.0.0.1"); */
            sin.sin_family = AF_INET;
            sin.sin_port = htons(PORT);

            sock_err = bind(sock, (struct sockaddr *) &sin, recsize);

            if(sock_err >= 0)
            {
                sock_err = listen(sock, MAX_CONNEC);
                printf(" -->Port %d configured\n", PORT);

                if(sock_err >= 0)
                {
                    printf(" -->Waiting for a client to connect to port %d...\n", PORT);

                    /* accept() thread */
                    pthread_create (&t1, NULL, server_first_thread, &send_to_thread);

/*--------------------------------------------------------------------------------------------*/
                        /* user interface */
                        while (1) {

                            printf("server >");

                            fgets(chaine, sizeof(chaine), stdin);
                            clean_buffer(chaine);

                            if (my_error != 0) {
                                break;
                            }
                            else if ( strcmp(chaine, commands[EXIT]) == 0 ) {
                                pthread_cancel(t1);
                                break;
                            }
                            else if (strcmp(chaine, commands[HELP]) == 0) {
                                puts(" Available commands : \n exit");
                            }
                        }
/*--------------------------------------------------------------------------------------------*/


          /*sock_err = send(csock, buffer, strlen(buffer), 0);

          if ( sock_err != SOCKET_ERROR ) {

          printf(" -->Sending : SUCCESS\n");
          }

          else
          printf(" -->Sending ERROR ! \n");*/
                for (int i = 0; i<7; i++) {
                    shutdown(csock[i], SHUT_RDWR);
                }
                }
                else
                    perror("listen");
            }
            else
                perror("bind");

                puts(" -->Client socket closing");
            for (int i = 0; i<7; i++) {
                shutdown(csock[i], SHUT_RDWR);
            }

                puts(" -->Serveur socket closing");

            shutdown(sock, SHUT_RDWR);

            puts(" -->Shutdown complete");
        }
    else {
        my_error = -1;
    }


    return my_error;
}

int
main () {

    char chaine[32] = {0}; // stores user's commands
    const char *commands[] =
    {"exit", "help", "connect", "start server", "start client"};
    int error = 0;


    while (1) {

        printf("main >");

        fgets(chaine, sizeof(chaine), stdin);
        clean_buffer(chaine);

        if (error != 0) {
            puts(" ---* Error detected! Exiting now *---");
            exit(error);
        }
        else if ( strcmp(chaine, commands[EXIT]) == 0 ) {
            break;
        }
        else if (strcmp(chaine, commands[START_CLIENT]) == 0) {
            puts(" Starting client");
            error = client_start(commands);
        }
        else if (strcmp(chaine, commands[START_SERVER]) == 0) {
            puts(" Starting server");
            error = server_start(commands);
        }
        else if (strcmp(chaine, commands[HELP]) == 0) {
            puts(" Available commands : \n exit\n start server\n start client");
        }

        for (int i = 0; i<32; i++) {
            chaine[i] = 0;
        }
    }

    return 0;
}

Woups, désolé je viens de m'apercevoir que le code n'est pas portable, j'ai écrit sous linux ...

Quelqu'un pourrait-il m'aider néanmoins ?

Mr_belette

Messages : 6
Date d'inscription : 12/07/2009
Age : 34
Localisation : Poitiers

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Accept: socket operation on non-socket

Message  -ed- le Lun 13 Juil 2009 - 12:41

Avec ce code :
Code:

#ifdef __cplusplus
#error Be sure you are using a C compiler...
#endif

#if defined (WIN32) || defined (_WIN32)

#include <winsock2.h>

enum
{
  SHUT_RD = 0,                /* No more receptions.  */
#define SHUT_RD        SHUT_RD
  SHUT_WR,                    /* No more transmissions.  */
#define SHUT_WR        SHUT_WR
  SHUT_RDWR                    /* No more receptions or transmissions.  */
#define SHUT_RDWR      SHUT_RDWR
};

#elif defined (linux) || defined (_POSIX_VERSION) || defined (_POSIX2_C_VERSION)\
 || defined (_XOPEN_VERSION)

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* close */
#include <unistd.h>

#define INVALID_SOCKET -1
#define SOCKET_ERROR -1

#define closesocket(s) close (s)
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;

#else
#error not defined for this platform
#endif

#include <stdio.h>
#include <stdlib.h>

#include <pthread.h>

/* macros ============================================================== */

#define PORT            6000
#define MAX_CONNEC      5

#define NELEM(a) (sizeof(a)/sizeof*(a))

/* constants =========================================================== */

enum
{ EXIT, HELP, CONNECT, START_SERVER, START_CLIENT };

/* types =============================================================== */

typedef struct
{

  int sock;
  int *csock;
  struct sockaddr_in csin;
  unsigned int crecsize;

}
S_socket;

/* structures ========================================================== */
/* private data ======================================================== */
/* private functions =================================================== */

/* ---------------------------------------------------------------------
  --------------------------------------------------------------------- */
static void psock_perror (char const *cmt)
{
#if defined (WIN32) || defined (_WIN32)

  fprintf (stderr, "%s: ", cmt);
  {
      DWORD err = WSAGetLastError ();
      wchar_t msg[1024];
      FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0,
                      msg, NELEM (msg), NULL);
      fwprintf (stderr, L"%s\n", msg);
  }

#elif defined (linux) || defined (_POSIX_VERSION) || defined (_POSIX2_C_VERSION)\
 || defined (_XOPEN_VERSION)

  perror (cmt);

#else
#error not defined for this platform
#endif

}



static void clean_buffer (char *chaine)
{

  char *p = strchr (chaine, '\n');
  int c;

  if (p)
  {
      *p = 0;
  }

  else
  {
      while ((c = getchar ()) != '\n' && c != EOF)
      {
      }
  }
}

static int client_start (const char **commands)
{

/* stores user's commands */
  char chaine[32] = { 0 };
  int my_error = 0;

  while (1)
  {

      printf ("client >");

      fgets (chaine, sizeof (chaine), stdin);
      clean_buffer (chaine);

      if (my_error != 0)
      {
        break;
      }
      else if (strcmp (chaine, commands[EXIT]) == 0)
      {
        break;
      }
      else if (strcmp (chaine, commands[CONNECT]) == 0)
      {
        puts (" Starting client");
/* error = ; */

      }
      else if (strcmp (chaine, commands[HELP]) == 0)
      {
        puts (" Available commands : \n exit\n connect");
      }
  }

  return my_error;
}

/* returns a freed place number from a socket(int) array */
static int find_unused_socket_number (int *array)
{

  int retval = -1;
  int i;
  for (i = 0; i < 7; i++)
  {
      if (array[i] == 0)
      {
        retval = i;
        break;
      }
  }

  return retval;
}

static void *server_first_thread (void *data)
{
  int free_number = 0;
  S_socket *socket_data = (S_socket *) data;
  unsigned int crecsize = (unsigned int) sizeof socket_data->csin;

  while (1)
  {

      free_number = find_unused_socket_number (socket_data->csock);

      if (free_number == -1)
      {
        pthread_exit (NULL);
      }

/* ACCEPT ----------------- */

      socket_data->csock[free_number] = accept (socket_data->sock,
                                                (struct sockaddr *)
                                                &socket_data->csin,
                                                &crecsize);

      if (socket_data->csock[free_number] != INVALID_SOCKET)
      {

        printf (" -->One client connected from %s\n",
                inet_ntoa (socket_data->csin.sin_addr));
      }
      else
      {
        psock_perror ("accept");
        break;
      }
  }

  return (void *) NULL;
}

static int server_start (const char **commands)
{

/* stores user's commands */
  char chaine[32] = { 0 };
  int my_error = 0;

/* char *buffer = "bonjour"; */

  pthread_t t1;

/* server side */

  struct sockaddr_in sin;
  int sock = 0;
  unsigned int recsize = (unsigned int) sizeof sin;

/* client side */

  struct sockaddr_in csin;
  int csock[7] = { 0 };
/* unsigned int crecsize = (unsigned int) sizeof csin; */

  S_socket send_to_thread = { 0 };

  int sock_err;

  send_to_thread.sock = sock;
  send_to_thread.csock = csock;
  send_to_thread.csin = csin;
  sock = socket (AF_INET, SOCK_STREAM, 0);

  if (sock >= 0)
  {
      printf (" -->Socket %d is now opened in TCP/IP mode\n", sock);

/* htonl(INADDR_ANY); OR inet_addr("127.0.0.1"); */
      sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
      sin.sin_family = AF_INET;
      sin.sin_port = htons (PORT);

      sock_err = bind (sock, (struct sockaddr *) &sin, recsize);

      if (sock_err >= 0)
      {
        sock_err = listen (sock, MAX_CONNEC);
        printf (" -->Port %d configured\n", PORT);

        if (sock_err >= 0)
        {
            printf (" -->Waiting for a client to connect to port %d...\n",
                    PORT);

/* accept() thread */

            pthread_create (&t1, NULL, server_first_thread, &send_to_thread);

/*--------------------------------------------------------------------------------------------*/
/* user interface */

            while (1)
            {

              printf ("server >");

              fgets (chaine, sizeof (chaine), stdin);
              clean_buffer (chaine);

              if (my_error != 0)
              {
                  break;
              }
              else if (strcmp (chaine, commands[EXIT]) == 0)
              {
                  pthread_cancel (t1);
                  break;
              }
              else if (strcmp (chaine, commands[HELP]) == 0)
              {
                  puts (" Available commands : \n exit");
              }
            }
/*--------------------------------------------------------------------------------------------*/

/*sock_err = send(csock, buffer, strlen(buffer), 0);

          if ( sock_err != SOCKET_ERROR ) {

          printf(" -->Sending : SUCCESS\n");
          }

          else
          printf(" -->Sending ERROR ! \n");*/
            {
              int i;
              for (i = 0; i < 7; i++)
              {
                  shutdown (csock[i], SHUT_RDWR);
              }
            }
        }
        else
            psock_perror ("listen");
      }
      else
        psock_perror ("bind");

      puts (" -->Client socket closing");
      {
        int i;
        for (i = 0; i < 7; i++)
        {
            shutdown (csock[i], SHUT_RDWR);
        }
      }

      puts (" -->Serveur socket closing");

      shutdown (sock, SHUT_RDWR);

      puts (" -->Shutdown complete");
  }
  else
  {
      my_error = -1;
  }

  return my_error;
}

static int app (void)
{

/* stores user's commands */
  char chaine[32] = { 0 };
  const char *commands[] =
      { "exit", "help", "connect", "start server", "start client" };
  int error = 0;

  while (1)
  {

      printf ("main >");

      fgets (chaine, sizeof (chaine), stdin);
      clean_buffer (chaine);

      if (error != 0)
      {
        puts (" ---* Error detected! Exiting now *---");
        exit (error);
      }
      else if (strcmp (chaine, commands[EXIT]) == 0)
      {
        break;
      }
      else if (strcmp (chaine, commands[START_CLIENT]) == 0)
      {
        puts (" Starting client");
        error = client_start (commands);
      }
      else if (strcmp (chaine, commands[START_SERVER]) == 0)
      {
        puts (" Starting server");
        error = server_start (commands);
      }
      else if (strcmp (chaine, commands[HELP]) == 0)
      {
        puts (" Available commands : \n exit\n start server\n start client");
      }

      {
        int i;
        for (i = 0; i < 32; i++)
        {
            chaine[i] = 0;
        }
      }

  }

  return 0;
}

/* entry point ========================================================= */

/* ---------------------------------------------------------------------
  --------------------------------------------------------------------- */
int main (void)
{
  int ret;

#if defined (WIN32) || defined (_WIN32)
  WSADATA wsa_data;
  int err = WSAStartup (MAKEWORD (2, 2), &wsa_data);

  if (!err)
  {
      puts ("WIN: winsock2: OK");
  }
#else
  int err = 0;
  {
#endif
      if (!err)
      {
        app ();
      }
#if defined (WIN32) || defined (_WIN32)
      WSACleanup ();
#else
  }
#endif

  if (err)
  {
      ret = EXIT_FAILURE;
  }
  else
  {
      ret = EXIT_SUCCESS;
  }

  return ret;
}

J'obtiens (windows) :

Code:

WIN: winsock2: OK
main >start server
 Starting server
 -->Socket 76 is now opened in TCP/IP mode
 -->Port 6000 configured
 -->Waiting for a client to connect to port 6000...
server >accept: Une opÚration a ÚtÚ tentÚe sur autre chose qu'un socket.


server >exit
 -->Client socket closing
 -->Serveur socket closing
 -->Shutdown complete
main >exit

Process returned 0 (0x0)  execution time : 30.594 s
Press any key to continue.
Il y a donc un bug dans l'appel de accept()... C'est bien le socket du serveur qui a été passé en paramètre ?

J'ajoute une trace pour voir ce qui se passe :

Code:

/* ACCEPT ----------------- */

      /* -ed- trace : */
      printf("SRV: socket_data->sock = %d\n", socket_data->sock);

      socket_data->csock[free_number] = accept (socket_data->sock,
                                                (struct sockaddr *)
                                                &socket_data->csin,
                                                &crecsize);
visiblement, tu as oublié de passer la valeur du socket serveur...
Code:

WIN: winsock2: OK
main >start server
 Starting server
 -->Socket 76 is now opened in TCP/IP mode
 -->Port 6000 configured
 -->Waiting for a client to connect to port 6000...
server >SRV: socket_data->sock = 0
accept: Une opÚration a ÚtÚ tentÚe sur autre chose qu'un socket.
<...>
J'ajoute le code manquant :
Code:

  sock = socket (AF_INET, SOCK_STREAM, 0);

  if (sock >= 0)
  {
      printf (" -->Socket %d is now opened in TCP/IP mode\n", sock);

      /* -ed- correction */
      send_to_thread.sock = sock;

et ...
Code:

WIN: winsock2: OK
main >start server
 Starting server
 -->Socket 76 is now opened in TCP/IP mode
 -->Port 6000 configured
 -->Waiting for a client to connect to port 6000...
server >SRV: socket_data->sock = 76
 -->One client connected from 127.0.0.1
SRV: socket_data->sock = 76

server >exit
 -->Client socket closing
 -->Serveur socket closing
 -->Shutdown complete
main >exit

Process returned 0 (0x0)  execution time : 42.152 s
Press any key to continue.
J'espère que tu as compris l'essentiel, c'est à dire la méthode de mise au point...

Ne rien supposer, ne faire confiance qu'en ce qu'on voit...

_________________
C is a sharp tool !

-ed-
Admin
Admin

Messages : 289
Date d'inscription : 26/05/2008
Age : 60
Localisation : Paris 6eme arrondissement (75, France)

Voir le profil de l'utilisateur http://bien-programmer.fr

Revenir en haut Aller en bas

Merci

Message  Mr_belette le Lun 13 Juil 2009 - 14:00

En effet, je vois : j'avais passé à ma structure de données un socket pas encore initialisé avec la fonction socket()...
Que dire, on imagine toujours que ces défaillances d'attention sont derrière soit, mais non.

Merci beaucoup de votre attention !

Bonne journée à tous,

Matthieu

Mr_belette

Messages : 6
Date d'inscription : 12/07/2009
Age : 34
Localisation : Poitiers

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Accept: socket operation on non-socket

Message  Contenu sponsorisé Aujourd'hui à 15:29


Contenu sponsorisé


Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum