Newsgroup: it.comp.programmare
Titolo: Passaggio struct con socket (lungo)

Scusate se insisto coi miei problemi sulla programmazione client-server
mediante socket unix in dominio tcp-ip ma sto incontrando parecchi
problemini...
Lo strano "fenomeno" che ho rilevato e` che praticamente la mia
applicazione distribuita gira solo sulla stessa macchina e toppa se
lancio server e client da macchine diverse.
Mi spiego meglio, lancio il server su una macchina, a video compare il
numero di porta su cui e` in attesa il server, mi sposto sull'altra e
batto client nome-macchina-server #porta-server, il client si connette
regolarmente, il server lo accetta ma quando a sua volta cerca di
connettersi al client (e` richiesto dalle specifiche) per chiudere
l'anello fallisce proprio sulla connect con errore:
"Connection refused"
I dati per fare la connessione arrivano al server dal client con
read/write, cioe` faccio riempiere al client una struttura di tipo
sock_addr_in coi dati della socket passiva aperta che poi viene passata
con la write al server che a sua volta li legge dalla struttura e li
ricopia nella struttura sock_addr_in "vera" della socket di connessione
che sta aprendo per connettersi.
Ho controllato il codice piu` volte senza trovare soluzioni. Tenete
conto poi che lasciando tutto localhost funziona a meraviglia.
Avete idee?
Sto commettendo qualche errore madornale senza accorgermene?
Puo` essere che ci siano errori gravi mascherati fintanto si vada in
localhost?
Visto che le macchine su cui faccio la prova hanno nome noto ho provato
a far scrivere dal server stesso l'indirizzo della macchina cosiccome fa
il client ed ha funzionato. Cioe`:
prendendosi solo i campi sin_family e sin_port dalla struttura passata
dal client mediante write e unendo a questi l'indirizzo ricavato dal
sistema (gethostbyname) il server riesce a connettersi tranquillamente
al client. Se invece prende anche l'indirizzo leggendolo dalla struttura
compilata dal client toppa. Perche`?
Non e` sufficiente passargli il campo sin_addr.s_addr? Ho provato anche
a passare sin_addr soltanto o tutti e 2 ma non e` cambiato nulla.
Forse che, lato client, devo fare qualche operazione preventiva sulla
struttura sock_addr_in che poi voglio passare al server tramite write?
Ecco i pezzi di codice incriminati (msg e` la struttura che contiene a
sua volta una struttura di tipo sock_addr_in):
1)
CODICE CLIENT:
  ...
  /*crea socket per ricevere da anello*/
  sock_p = socket(AF_INET, SOCK_STREAM, 0);
  s_p.sin_family = AF_INET;           /*protocol suite*/
  s_p.sin_addr.s_addr = INADDR_ANY;   /*IP Address*/
  s_p.sin_port = 0;                    /*port*/
  lungh_s_p = sizeof s_p;
  bind(sock_p, &s_p, lungh_s_p)
  listen(sock_p, 5);
  /*crea la socket per connettersi al server*/
  sock_a = socket(AF_INET, SOCK_STREAM, 0);
  /*prende come host l'argomento e ritorna il puntatore struttura
indirizzo host*/
  hp_a = gethostbyname (argv[1]);
  if(hp_a == 0)
  {
    fprintf(stderr, "%s:unknown host\n", argv[1]);
    exit(2);
  }
  (void) bcopy((char*)hp_a->h_addr, (char*)&s_a.sin_addr,
hp_a->h_length);
  s_a.sin_family = AF_INET;             /*protocol suite*/
  s_a.sin_port =htons(atoi(argv[2]));   /*port*/
  lungh_s_a = sizeof s_a;
  /*connessione al server*/
  if(connect(sock_a, &s_a, lungh_s_a)<0)
  {
    printf("errore di connessione\n");
    exit(1);
  }
  /*scrive indirizzo nuova porta dove deve trasmettere*/
  /* il server*/
  msg.codice="X";
  msg.fsin.sin_family=s_p.sin_family;
  msg.fsin.sin_addr.s_addr=s_p.sin_addr.s_addr;
  msg.fsin.sin_port=s_p.sin_port;
  if(write(sock_a, &msg, sizeof msg)<0)
    printf("errore di write\n");
  ...
CODICE SERVER;
        ...
        read(fd, &msg, sizeof msg);
        switch(msg.codice)
        ...
        case "X":/*ricezione dati da nuovo client*/
          /*crea socket per trasmettere messaggi sull'anello*/
          sock_a = socket(AF_INET, SOCK_STREAM, 0);
          /*inizializza struttura attiva server*/
          s_a.sin_family=msg.fsin.sin_family;
          s_a.sin_addr.s_addr=msg.fsin.sin_addr.s_addr;
          s_a.sin_port=msg.fsin.sin_port;
          lungh_s_a = sizeof s_a;
          /*connessione al client*/
          if(connect(sock_a, &s_a, lungh_s_a)<0)
          {
            printf("errore di connessione\n");
            exit(1);
          }
          ...
Questo fallisce sulla connect del server verso il client!!!
A parte localhost
2)
CODICE CLIENT resta lo stesso
CODICE SERVER:
        read(fd, &msg, sizeof msg);
        switch(msg.codice)
        ...
        case "X":/*ricezione dati da nuovo client*/
          /*crea socket per trasmettere messaggi sull'anello*/
          sock_a = socket(AF_INET, SOCK_STREAM, 0);
         /*prende come host il nome di macchina (NOTO!)*/
         hp_a = gethostbyname ("nome_host_server");
         if(hp_a == 0)
         {
           fprintf(stderr, "unknown host\n");
           exit(2);
         }
         (void) bcopy((char*)hp_a->h_addr, (char*)&s_a.sin_addr,
hp_a->h_length);
          /*inizializza resto della struttura attiva server*/
          s_a.sin_family=msg.fsin.sin_family;
          s_a.sin_port=msg.fsin.sin_port;
          lungh_s_a = sizeof s_a;
          /*connessione al client*/
          if(connect(sock_a, &s_a, lungh_s_a)<0)
          {
            printf("errore di connessione\n");
            exit(1);
          }
          ...
Questo funziona!!!
Saluti e grazie
-- 
Giuseppe R.
E-mail: mailto:
giuseppe...@SPAMnetit.alcatel.it
--
Posted from 
ns.alcanet.it
 [194.243.74.35] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

Se a qualcuno interessa ho risolto il problema per tentativi ed aiuti.
Ad essere sincero non ho capito fino in fondo perche` adesso si chiude
l'anello ma alla base c'era effettivamente il passaggio della struttura
sock_addr_in da un processo all'altro.
Il ragionamento e` stato quello di duplicare quello che viene fatto dal
client per acquisire i dati dal server. Con la differenza che, per il
client, il server e` noto e quindi sa come recuperare i suoi dati, per
il server il client non e` noto e per connettersi su di lui deve per
forza entrare in contatto dei suoi dati, in altre parole e` il client
stesso che DEVE passarglieli in qualche modo.
Definita la struttura:
  struct hostent *hp_b;      /*struttura per mettere a disposizione
dati*/
e il buffer:
  char localhost[33];
e creata la socket passiva da cui il client riceve:
  sock_p = socket(AF_INET, SOCK_STREAM, 0);
  if (sock_p <0...)
  s_p.sin_family = AF_INET;           /*protocol suite*/
  s_p.sin_addr.s_addr = INADDR_ANY;   /*IP Address*/
  s_p.sin_port = 0;                    /*port*/
  lungh_s_p = sizeof s_p;
  if (bind(sock_p, &s_p, lungh_s_p)<0...)
Ho aggiunto la seguente parte:
  gethostname(localhost, 32);
  hp_b = gethostbyname (localhost);
  if(hp_b == 0)
  {
    fprintf(stderr, "localhost: unknown host\n");
    exit(2);
  }
  (void) bcopy((char*)hp_b->h_addr, (char*)&s_p.sin_addr,
hp_b->h_length);
Poi il client prosegue normalmente, apre una socket attiva, con questa
si connette al server, viene accettato, e gli passa i dati della sua
socket passiva mediante write.
  if(write(sock_a, &struct-x, sizeof struct-x)<0...)
Dove naturalmente la struct-x contiene la struttura di tipo sock_addr_in
riempita poc'anzi (s_p).
Adesso funziona anche se l'ho testata poco. Prima dell'aggiunta della
gethostname, gethostbyname non c'era verso. Come che queste due funzioni
siano NECESSARIE per riempire a dovere la struttura sock_addr_in. La
cosa non mi soddisfa del tutto e infatti vi chiedo un parere. E` tutto
corretto o e` un miraggio? Oppure sto mascherando l'errore con un altro
errore?
---
Domanda d'appendice:
non mi e` chiara la differenza dei campi .sin_addr e .sin_addr.s_addr
all'interno della struttura sock_addr_in, voglio dire sono ridondanti o
servono entrambe per definire la socket? Io passo il primo dei due e la
cosa sembra funzionare.
La domanda puo` essere generalizzata, se una struttura x contiene una
sottostruttura y oltre ad altri campi, il passaggio con socket di x mi
garantisce di passare tutto?
