Problema Socket ( accept ritorna 0 )

di il
3 risposte

Problema Socket ( accept ritorna 0 )

Mando in esecuzione un client e un server che dovrebbero fare le seguenti cose

Server:
Creazione Socket_S
Accept bloccante su Socket_s

Client:
Crea una sua socket ... chiamiamola Socket_C
tentativo di connettersi alla Socket_S e Invio messaggio
Accept bloccante su Socket_C

Server:
Riceve messaggio estrapola da esso il path per Socket_C
Tenta di connettersi a Socket_C
Invia il messaggio

Client: si risveglia tenta di leggere il messaggio ma si blocca

Ho notato che la accept ritorna 0 (nonostante non ho chiuso stdin), però comunque non da errore cosa a mio parere strana ma la read quando va a leggere da 0 si blocca


Libreria
/**  \file  comsock.c
 *   \brief libreria di comunicazione socket AF_UNIX
 *
 *    \author Diego Capasso
*/

#include "comsock.h"


/* -= FUNZIONI =- */
/** Crea una socket AF_UNIX
 *  \param  path pathname della socket
 *
 *  \retval s    il file descriptor della socket  (s>0)
 *  \retval -1   in altri casi di errore (setta errno)
 *               errno = E2BIG se il nome eccede UNIX_PATH_MAX
 *
 *  in caso di errore ripristina la situazione inziale: rimuove eventuali socket create e chiude eventuali file descriptor rimasti aperti
 */
int createServerChannel(char* path)
{
  int fd_skt;
  struct sockaddr_un sa;
  
  if ( strlen (path) > UNIX_PATH_MAX )
  {
    errno=E2BIG;
    return -1;
  }
  
  strncpy(sa.sun_path, path, UNIX_PATH_MAX );
  sa.sun_family=AF_UNIX;
  fd_skt=socket (AF_UNIX, SOCK_STREAM, 0);
  if( fd_skt == -1 )
  {
    errno= EACCES;
    return -1;
  }
  
  if ( bind(fd_skt, ((struct sockaddr *) &sa ), sizeof(sa)) != 0 )
  {
    close ( fd_skt ); 
    return -1;
  }
    
  if ( listen( fd_skt, 1 ) != 0 )
  {
    close ( fd_skt );
    return -1;
  }
    
  return fd_skt;
}

/** Chiude una socket
 *   \param s file descriptor della socket
 *
 *   \retval 0  se tutto ok, 
 *   \retval -1  se errore (setta errno)
 */
int closeSocket(int s)
{
  return close( s ); 
}

/** accetta una connessione da parte di un client
 *  \param  s socket su cui ci mettiamo in attesa di accettare la connessione
 *
 *  \retval  c il descrittore della socket su cui siamo connessi
 *  \retval  -1 in casi di errore (setta errno)
 */
int acceptConnection(int s)
{
  return  accept ( s, NULL, 0 );
}

/** legge un messaggio dalla socket --- attenzione si richiede che il messaggio sia adeguatamente spacchettato e trasferito nella struttura msg
 *  \param  sc  file descriptor della socket
 *  \param msg  struttura che conterra' il messagio letto 
 *		(deve essere allocata all'esterno della funzione,
 *		tranne il campo buffer)
 *
 *  \retval lung  lunghezza del buffer letto, se OK 
 *  \retval  -1   in caso di errore (setta errno)
 *                 errno = ENOTCONN se il peer ha chiuso la connessione 
 *                   (non ci sono piu' scrittori sulla socket)
 *      
 */
int receiveMessage(int sc, message_t * msg)
{
  char *buffer;
  int n,i;

  if ( (n = read( sc , &(msg->type) , sizeof(char)) )== 0 ) 
  {
    errno= ENOTCONN;
    return -1;
  }
  else if ( n == -1 )
    return -1; 

  
  if ( (n = read( sc , &(msg->length), sizeof( unsigned int) ) ) == 0 ) 
  {
    errno= ENOTCONN;
    return -1;
  }
  else if ( n == -1 )
    return -1; 
  
  
  buffer = malloc(sizeof(char)*msg->length ); 
  if ( ( n = read( sc , buffer, (sizeof(char)*(msg->length)) ) ) == 0 ) 
  {
    errno= ENOTCONN;
    return -1;
  }
  else if ( n == -1 )
    return -1;
  
  msg->buffer = buffer;
  
  
  return n;
}


/** scrive un messaggio sulla socket --- attenzione si richiede che il messaggio venga scritto con un'unica write dopo averlo adeguatamente impacchettato
 *   \param  sc file descriptor della socket
 *   \param msg struttura che contiene il messaggio da scrivere 
 *   
 *   \retval  n    il numero di caratteri inviati (se scrittura OK)
 *   \retval -1   in caso di errore (setta errno)
 *                 errno = ENOTCONN se il peer ha chiuso la connessione 
 *                   (non ci sono piu' lettori sulla socket)
 */
int sendMessage(int sc, message_t *msg)
{
  void *dest;
  int n;
  
  dest=malloc( (sizeof(unsigned int) + sizeof (char) + sizeof (char)*msg->length) );
  
  if(dest==NULL)
  {
    errno=ENOMEM;
    return -1; 
  }
  
  memcpy( dest, &(msg->type), sizeof(char) );
  memcpy( (dest+ sizeof(char)) , &(msg->length), sizeof(unsigned int) );
  memcpy( (dest+sizeof(char)+sizeof(unsigned int)) , msg->buffer, (sizeof(char)*(msg->length)) );

  
  if ( ( n = write ( sc, dest, sizeof(unsigned int)+sizeof(char)*(1+msg->length) ) ) == 0 )
  {
    free ( dest );
    return -1;
  }
    
  return n;
  
}


/** crea una connessione all socket del server. In caso di errore funzione tenta NTRIALCONN volte la connessione (a distanza di 1 secondo l'una dall'altra) prima di ritornare errore.
 *   \param  path  nome del socket su cui il server accetta le connessioni
 *   
 *   \return fd il file descriptor della connessione
 *            se la connessione ha successo
 *   \retval -1 in caso di errore (setta errno)
 *               errno = E2BIG se il nome eccede UNIX_PATH_MAX
 *
 *  in caso di errore ripristina la situazione inziale: rimuove eventuali socket create e chiude eventuali file descriptor rimasti aperti
 */
int openConnection(char* path)
{
  int fd_skt,n=0;
  struct sockaddr_un sa;
  
  if ( strlen ( path ) > UNIX_PATH_MAX )
  {
    errno=E2BIG;
    return -1;
  }
  
  strncpy(sa.sun_path, path, UNIX_PATH_MAX );
  sa.sun_family=AF_UNIX;
  fd_skt = socket ( AF_UNIX, SOCK_STREAM, 0 );
  
  while ( connect ( fd_skt, (struct sockaddr* ) &sa, sizeof(sa) ) == -1 )
  {
    if ((errno = ENOENT )&&( n < NTRIALCONN)) 
    {
      n++;
      sleep (1);
    }
    else
    {
      close (fd_skt);
      return -1;
    }
  }
  
  return fd_skt;
}


Server
#include "./lib/dgraph.c"
#include "./lib/comsock.c"
#include "./lib/lista.c"
#include <unistd.h>

#define SOCK_PATH "./tmp/cars.sck"
#define LOG_PATH "./mgcars.log"
#define LONG_USER 30
#define LONG_PWD  30

#define CLEAN {remove(SOCK_PATH);free(msg);fclose(pLog);fclose(pCitta);fclose(pStrade);}
#define CLOSE(when,status) { perror(when);CLEAN;exit(status);}

/* Struttura che verra' passata come parametro agli worker */
typedef struct argomenti
{
  /* Dati account */
  char *buffer;
  int length;
  /* Lista account */
  list_t lista;
}arg_t;


void * worker_code ( void * argument )
{
  arg_t *data = (struct arg_t*) argument;
  int i,x=0,y=0;
  char *buffer= data->buffer;
  char b[3][100];
  int cl_skt;
  message_t *msg= malloc( sizeof(message_t) );
  
  printf( "Inizio WORKER\n");
  
  for( i=0; i< (data->length); i++)
  {
    printf("-%c-",buffer[i]);
    if( buffer[i] != '\0' )
    {
      b[x][y]=buffer[i];
      y++;
    }
    else
    {
      b[x][y]=buffer[i];
      y=0;
      x++;
    }
  }  
  printf("\nUSER_ID:|%s|\nPASSWORD:|%s|\nSOCKET|%s|\n", b[0],b[1],b[2]);
  
  
  
  /*switch ( presente( data->lista, b[0], b[1] ) ){
    case (-1):		
      break;
    case 1:		
      data->lista= ins_ord( data->lista, b[0], b[1] );
      printf("Account inserito: %d\n",presente( data->lista, b[0], b[1] ) );
    default:		
      break;
  }*/
 
  /* Connessione alla socket del client */
  for(i=0; i<NTRIALCONN; i++)
  {
    printf("Tentativo %d connessione a |%s|\n",(i+1),b[2]);
    if ( (cl_skt = openConnection(b[2])) != -1 )
    { 
      printf("Mi sono connesso a |%s|\n",b[2]);  
      break;
      
    }
  }
  if ( cl_skt == -1 )
  {
    perror("Apertura socket:");
    exit(-1);
  }
  printf("Connessi alla socket del server: |%s|%d|, PRONTI AL LOGIN\n",b[2],cl_skt);
  errno=0;

  msg->type='K';
  msg->length = strlen("Account confermato");
  msg->buffer=malloc(sizeof(char)*msg->length+1);
  strcpy(msg->buffer,"Account confermato\0");
  
  if ( sendMessage(cl_skt, msg) == -1 )
    perror("SEND NON HA AVUTO SUCCESSO:");
  
  receiveMessage(cl_skt, msg);
  printf("|%c|%d|%s|\n",msg->type,msg->length,msg->buffer);
  
  
  printf("fine del worker server\n");
      
}
  
  

int main ( int argc , char *argv[] )
{
  
  FILE * pCitta, * pStrade, *pLog;
  graph_t *grafo;
  arg_t argo;
  list_t lista=NULL;
  int sr_skt;
  int x,y,i;
  char b[3][100];
  message_t *msg;
  msg = malloc( sizeof(message_t) );
  
  if( argc != 3 ){
    printf("Parametri non corretti, esempio: mgcars file_citta file_strade\n");
    exit (-1);
  }
  if ( ( access( argv[1], R_OK ) ) || ( access ( argv[2], R_OK ) ) )  {
    printf("Mancano i permessi di lettura sui file di input\n");
    exit (-1);
  }
  
  if( (pCitta = fopen ( argv[1] ,"rt")) == NULL )
    CLOSE("Apertura file citta:",-1);
  
  
  if( (pStrade = fopen ( argv [2] , "rt")) == NULL )
    CLOSE("Apertura file strade:",-1);
  
  if( (grafo = load_graph (pCitta,pStrade)) == NULL )
    CLOSE("Caricamento grafo:",-1);
  /* Log File */
  if( (pLog = fopen ( LOG_PATH, "rw" )) == NULL )
    CLOSE("Apertura file log",-1);
  /* Apertura socket Server */
  if ( (sr_skt = createServerChannel(SOCK_PATH)) == -1 )
    CLOSE("Creazione Socket Server:",-1);
  /* Stampa di debug DA ELIMINARE! */  printf("Creata la socket %s\n",SOCK_PATH);
  /* Accettazione connessioni */
  if( (sr_skt = acceptConnection(sr_skt)) == -1 )
    CLOSE("Accettazione connessione su socket risposte:",-1);
  /* Ricezione Account */
  errno=0;
  while( 
  receiveMessage(sr_skt, msg );
  perror("RECIVE");

 
  argo.buffer=msg->buffer;
  argo.lista=lista;
  argo.length=msg->length;
  
  worker_code ( (void *)&argo );
  printf("fine server\n");
}

Client
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h> 
#include "./lib/comsock.c"
#include <pthread.h>

#define SOCK_PATH "./tmp/cars.sck"
#define CLEAN {remove(SOCK_PATH);free(msg);fclose(pLog);fclose(pCitta);fclose(pStrade);}
#define CLOSE(when,status) { perror(when);CLEAN;exit(status);}

/**************************************************************
 * Nome: Worker
 * Argomenti: Socket 
 * 
 * La prima funzione che viene chiamata all'avvio del thread
 * che si occupa di rimanere in ascolto sulla socket su cui
 * vengono inviate le risposte da parte del client
 * ***********************************************************/
void * worker( void * arg )
{
  int cl_skt = (int)arg;
  message_t *msg;
  msg=malloc(sizeof(message_t));
  
  printf("inizio worker client\n");
  
  /* Ascolto connessioni */
  if( cl_skt = acceptConnection(cl_skt) == -1 )
  {
    perror("Accettazione connessione su socket risposte:");
    exit(-1);
  }
  printf("-Accettazione completata-\n");
  errno=0;
  
  read( cl_skt , &(msg->type) , sizeof(char));
  printf("TYPE---->%c\n",msg->type);
  
  /* 
   * Ricezione messaggi 
  while ( errno!=ENOTCONN )
    if( receiveMessage( cl_skt, msg ) != -1 )
    {
      printf( "Risposta: %s\n", msg->buffer );
      free(msg->buffer);
    }
  printf("fine lettura messaggi");
  free(msg);
  closeSocket(cl_skt);
  return NULL;*/
}


int main ( int argc, char * argv[] )
{
  char pwd[100];
  char *buffer;
  char sock_name[100];
  int sr_skt,cl_skt,tid,i;
  pthread_t ptid;
  message_t *msg=malloc(sizeof(message_t));
  

  /* Controllo parametri */
  if ( argc != 2 ){
    printf("Parametri errati, inserire user_id\n");
    exit(-1);
  }
  
  printf("$%s: Inserire la password\n",argv[1]);
  if ( !(scanf("%s",pwd)) ){
    printf("Password troppo corta\n");
    exit(-1);
  }
  
  /* Creazione Socket_Client */
  tid = syscall(SYS_gettid);
  sprintf(sock_name,"%d_%s", tid, argv[1] );

  if ( (cl_skt = createServerChannel(sock_name)) == -1 )
  {
    perror("Creazione Socket Client:");
    exit(-1);
  }
  printf("\nCreata la socket |%s|\n",sock_name);
 
  
  /* Creazione Messaggio di Connessione */
  msg->type='C';
  msg->length = strlen(argv[1])+strlen(pwd)+strlen(sock_name)+3;
  buffer= malloc( sizeof(char)*msg->length );
  memcpy( buffer, argv[1], sizeof(char)*(strlen(argv[1])+1) );
  memcpy( buffer+(strlen(argv[1])+1), pwd, sizeof(char)*(strlen(pwd)+1) );
  memcpy( buffer+(strlen(argv[1])+strlen(pwd)+2), sock_name, sizeof(char)*(strlen(sock_name)+1) );
  msg->buffer=buffer;
  
  
  /* Tentativi connesione al socket del server */
  for(i=0; i<NTRIALCONN; i++)
  {
    if ( (sr_skt = openConnection(SOCK_PATH)) != -1 )
      break;
  }
  if ( sr_skt == -1 )
  {
    perror("Apertura socket:");
    exit(-1);
  }
  errno=0;

  if ( sendMessage(sr_skt, msg) == -1 )
    perror("SEND");
  printf("Messaggio inviato\n");    
  

  /*
  
  if( pthread_create( &ptid, NULL, &(worker), (void *) (cl_skt) ) )
  {
    perror("Creazione thread Client");
    exit(-1);
  }
  printf("Creato!\n");
  
  if ( pthread_join ( ptid, NULL ) ) {
    printf("error joining thread.");
    abort();
  }
  printf("Pthread finito\n");
  */
  
  if( cl_skt = acceptConnection(cl_skt) == -1 )
  {
    perror("Accettazione connessione su socket risposte:");
    exit(-1);
  }
  printf("-Accettazione completata-\n");
  errno=0;
  
  /*
   * read( cl_skt , &(msg->type) , sizeof(char));
  printf("TYPE---->%c\n",msg->type);
  */
  
  
  
}

So che ci sono tante blasfemie in questo codice a iniziare dai vari include di file.c però sono dei programmini che ho scritto solo per capire dove sbaglio nei due client e server completi

Spero qualcuno mi sappia aiutare Q__Q

Grazie

3 Risposte

  • Re: Problema Socket ( accept ritorna 0 )

    Non riesco a compilarlo in quanto mancano dei pezzi. Il problema secondo me è la mancanza delle parentesi.

    Prova a cambiare:
    
    if( cl_skt = acceptConnection(cl_skt) == -1 )
    
    in questo:
    
    if( (cl_skt = acceptConnection(cl_skt)) == -1 )
    
  • Re: Problema Socket ( accept ritorna 0 )

    Avevo risolto il problema senza sapere come, grazie a te so che compilerò sempre usando -Wall -pedantic ... dannate parentesi.

    Grazie infinite!

    PS: in compenso usando -Wall -pedantic sono saltati fuori questi


    ./lib/comsock.c: In function ‘sendMessage’:
    ./lib/comsock.c:151:16: warning: pointer of type ‘void *’ used in arithmetic [-pedantic]
    ./lib/comsock.c:152:16: warning: pointer of type ‘void *’ used in arithmetic [-pedantic]
    ./lib/comsock.c:152:29: warning: pointer of type ‘void *’ used in arithmetic [-pedantic]

    memcpy( dest, &(msg->type), sizeof(char) );
    memcpy( (dest+ sizeof(char)) , &(msg->length), sizeof(unsigned int) );
    memcpy( (dest+sizeof(char)+sizeof(unsigned int)) , msg->buffer, (sizeof(char)*(msg->length)) );

    Quale sarebbe il modo giusto di fare ciò?
    Mi serve necessariamente poter scrivere sulla socket con un unica write dunque in questo modo funziona però mi da quel messaggio come se non fosse propriamente corretto o.o
  • Re: Problema Socket ( accept ritorna 0 )

    Castare
Devi accedere o registrarti per scrivere nel forum
3 risposte