programmazione di rete con i socket

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
mr_simo
Prode Principiante
Messaggi: 59
Iscrizione: giovedì 8 novembre 2012, 12:01
Desktop: ubuntu -2d
Distribuzione: ubuntu 12.04 LTS
Località: Perugia

programmazione di rete con i socket

Messaggio da mr_simo »

Ciao !! Ho scritto un programmino che simula il gioco di un'asta di vendita: il processo padre(banditore) attende che N client(partecipanti) facciano un'offerta.. una volta fatto ciò, il banditore trova quella più alta, e invia ai client il pid del processo vincitore...

Per la comunicazione dei processi ho utilizzato i socket e le funzioni send() e recv().

il codice è il seguente:

Codice: Seleziona tutto

#include "libNET.h"

int main(int argc, char *argv[]){
    int sock_fd;
    int new_sock_fd[N];
    struct sockaddr_in server_addr, client_addr;
    char command, finish;
    socklen_t client_len;
    pid_t child;
    int i, j, k;
    msgsend *request = malloc(sizeof(msgsend)); /* struttura per inviare le offerte */
    msgreceive *answer = malloc(sizeof(msgreceive)); /* struttura per ricevere il pid del vincitore */
    int offer;
    int arrayOffer[N], arrayPid[N], buyer; /* array per il processo padre(server) */

    /* crea un socket */
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_fd < 0){
        perror("socket");
        exit(-1);
    }
    
    /* inizializza l'indirizzo del socket */
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);

    /* binding del socket */
    if(bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
        perror("bind ");
        exit(-1);
    }

    /* numero massimo di connessioni */
    listen(sock_fd, MAX_CONNECT);
    
    for(i=0; i<N; i++){
        child = fork();
        if(child < 0){
            perror("fork");
            exit(-1);
        }
        if(child == 0){/* processo figlio(client) */
            /* crea il socket */
            sock_fd = socket(AF_INET, SOCK_STREAM, 0);
            /* costruisce l'indirizzo del server */
            server_addr.sin_family = AF_INET;
            server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
            server_addr.sin_port = htons(SERVER_PORT);
            /* connette il socket alla porta */
            if(connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
                perror("connect");
                exit(-1);
            }
            offer = offerGenerator(); /* prepara l'offerta */
            child = getpid();
            request[i].offer = offer;
            request[i].pid = child;
            
            do{
                /* invio dell'offerta e del pid */
                if(send(sock_fd, request, sizeof(request), 0) < 0){
                    perror("client, send");
                    exit(-1);
                }
 
                if(i == N-1)
                    finish = 'f';
                
                if(recv(sock_fd, answer, sizeof(answer), 0) < 0){
                    perror("client, first recv");
                    exit(-1);
                }
            
                printf("\nSono il client %d, con pid %d e ho vinto l'offerta!!\n", i, answer->pid_win);

                if(recv(sock_fd, &command, sizeof(char), 0) < 0){
                    perror("client, second recv");
                    exit(-1);
                }

                
            }while(command != 's');
            /* chiude la connessione */
            close(sock_fd);
            exit(0);
        }
    }/* fine for */

    /* codice eseguito dal padre(banditore) */
    for(i=0; i<N; i++){
        /* accetta una connessione alla porta */
        new_sock_fd[i] = accept(sock_fd, (struct sockaddr *)&client_addr, &client_len);
        if(new_sock_fd[i] < 0){
            perror("accept");
            exit(-1);
        }
    }
  
    while(finish == 'f'){
        if(recv(new_sock_fd[i], request, sizeof(request), 0) < 0){
            perror("server recv");
            exit(-1);
        }
        for(k=0; k<N; k++){
            arrayOffer[k] = request[k].offer;
            arrayPid[k] = request[k].pid;
            printf("\noffer: %d  ||  pid: %d\n",arrayOffer[k], arrayPid[k]);
        }
        buyer = searchMaxOffer(arrayOffer, N);
        answer->pid_win = arrayPid[buyer];
        command = 's';
        for(j=0; j<N; j++){
             if(send(new_sock_fd[j], answer, sizeof(answer), 0) < 0){
                 perror("server first send");
                 exit(-1);
             }
             sleep(N);
             if(send(new_sock_fd[j], &command, sizeof(char), 0) < 0){
                 perror("server second send");
                 exit(-1);
             }
             close(new_sock_fd[j]);
        }
    }

    




    return 0;
}
una volta lanciato mi da il seguente errore:

Codice: Seleziona tutto

client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
*** Error in `./Starter': free(): invalid next size (normal): 0x0000000001c5c050 ***
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x80996)[0x7f6f7609f996]
/lib/x86_64-linux-gnu/libc.so.6(fclose+0x14d)[0x7f6f7608d9bd]
./Starter[0x400df6]
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
mr_simo@mrsimo-Aspire-5820TG:~/Scrivania/ASS_THREE$ ./Starter
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
*** Error in `./Starter': free(): invalid next size (normal): 0x0000000001987050 ***
client, first recv: Connection reset by peer
client, first recv: Connection reset by peer
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x80996)[0x7fc10379a996]
client, first recv: Connection reset by peer
/lib/x86_64-linux-gnu/libc.so.6(fclose+0x14d)[0x7fc1037889bd]
./Starter[0x400df6]
client, first recv: Connection reset by peer
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7fc10373bde5]
./Starter[0x400ac9]
======= Memory map: ========
client, first recv: Connection reset by peer
00400000-00402000 r-xp 00000000 08:05 8804857                            /home/mr_simo/Scrivania/ASS_THREE/Starter
00601000-00602000 r--p 00001000 08:05 8804857                            /home/mr_simo/Scrivania/ASS_THREE/Starter
00602000-00603000 rw-p 00002000 08:05 8804857                            /home/mr_simo/Scrivania/ASS_THREE/Starter
01987000-019a8000 rw-p 00000000 00:00 0                                  [heap]
7fc103504000-7fc103519000 r-xp 00000000 08:05 7471109                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc103519000-7fc103718000 ---p 00015000 08:05 7471109                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc103718000-7fc103719000 r--p 00014000 08:05 7471109                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc103719000-7fc10371a000 rw-p 00015000 08:05 7471109                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fc10371a000-7fc1038d7000 r-xp 00000000 08:05 7474995                    /lib/x86_64-linux-gnu/libc-2.17.so
7fc1038d7000-7fc103ad7000 ---p 001bd000 08:05 7474995                    /lib/x86_64-linux-gnu/libc-2.17.so
7fc103ad7000-7fc103adb000 r--p 001bd000 08:05 7474995                    /lib/x86_64-linux-gnu/libc-2.17.so
7fc103adb000-7fc103add000 rw-p 001c1000 08:05 7474995                    /lib/x86_64-linux-gnu/libc-2.17.so
7fc103add000-7fc103ae2000 rw-p 00000000 00:00 0 
7fc103ae2000-7fc103b05000 r-xp 00000000 08:05 7474971                    /lib/x86_64-linux-gnu/ld-2.17.so
7fc103ce5000-7fc103ce8000 rw-p 00000000 00:00 0 
7fc103d01000-7fc103d02000 rw-p 00000000 00:00 0 
7fc103d02000-7fc103d04000 rw-p 00000000 00:00 0 
7fc103d04000-7fc103d05000 r--p 00022000 08:05 7474971                    /lib/x86_64-linux-gnu/ld-2.17.so
7fc103d05000-7fc103d07000 rw-p 00023000 08:05 7474971                    /lib/x86_64-linux-gnu/ld-2.17.so
7fff88737000-7fff88758000 rw-p 00000000 00:00 0                          [stack]
7fff887fe000-7fff88800000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsysca

sto guardando sul man e da quanto ho capito dovrebbe essere un problema di dimensione dei dati da scambiare, ma non so dove mettere le mani...
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: programmazione di rete con i socket

Messaggio da ixamit »

mr_simo ha scritto:.... ma non so dove mettere le mani...
Le mani le devi mettere sugli strumenti di debug :D , ma anche sul codice che hai postato, visto che manca l'header ed un paio di funzioni (sempre se vuoi un aiuto)

Ad occhio vedo degli errori qui:

Codice: Seleziona tutto

   ...
    for(i=0; i<N; i++){
        /* accetta una connessione alla porta */
          ....
    }

    while(finish == 'f'){
        if(recv(new_sock_fd[i], request, sizeof(request), 0) < 0){
            ....
        }
    }
    return 0;
          ....     

   ...   
oltre l'errore di 'i' che vale N sulla while, non è corretta la gestione della flag finish (inoltre non inizializzata) settata dopo l'ultima fork, e che non ti fa entrare nella recv terminando sulla return del main.
L'errore sulla free (che non vedo nel codice) potrebbe derivare forse da una close di un socket id invalido, per cui collegabile al contesto precedente.

Comunque il mio consiglio è di imparare ad usare gli strumenti preposti per la maggior parte degli errori visibili e non.
mr_simo
Prode Principiante
Messaggi: 59
Iscrizione: giovedì 8 novembre 2012, 12:01
Desktop: ubuntu -2d
Distribuzione: ubuntu 12.04 LTS
Località: Perugia

Re: programmazione di rete con i socket

Messaggio da mr_simo »

In teoria dovrei utilizzare i segnali in modo che una volta che tutti i partecipanti hanno inviato le offerte lo segnalano al padre, il padre valuta l'offerta più alta e poi invia il pid del vincitore a tutti i partecipanti....Quindi è più appropriato mettere la recv all'interno del for e "avviarla" con un segnale?

Codice: Seleziona tutto

 for(i=0; i<N; i++){
        /* accetta una connessione alla porta */
          ....

       if(recv(new_sock_fd[i], request, sizeof(request), 0) < 0){
            ....
        }
    }
oppure fare un'altro ciclo esterno che si attiva una volta che il padre ha ricevuto il segnale??
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: programmazione di rete con i socket

Messaggio da ixamit »

mr_simo [url=http://forum.ubuntu-it.org/viewtopic.php?p=4595313#p4595313][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Quindi è più appropriato mettere la recv all'interno del for e "avviarla" con un segnale?
...
oppure fare un'altro ciclo esterno che si attiva una volta che il padre ha ricevuto il segnale??
Potresti usare la select.
Inoltre, perchè non spezzi quel programma usando delle funzioni? Risulterebbe più leggibile
mr_simo
Prode Principiante
Messaggi: 59
Iscrizione: giovedì 8 novembre 2012, 12:01
Desktop: ubuntu -2d
Distribuzione: ubuntu 12.04 LTS
Località: Perugia

Re: programmazione di rete con i socket

Messaggio da mr_simo »

si infatti scriverò delle funzioni ...Posso provare a usare la select(), anche se da testo dell'esercizio:
L'asta prosegue quindi fino a quando il banditore
non riceve il segnale SIGUSR1. A questo punto spedisce il segnale SIGUSR2 a
tutti i partecipanti. Quando un partecipante riceve il segnale termina (in modo
"pulito", ovvero deallocando le risorse, ecc, ecc.). Terminati tutti i partecipanti
anche il banditore termina (anche esso in modo "pulito",...)
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: programmazione di rete con i socket

Messaggio da ixamit »

Segui la traccia.
La select() la vedevo meglio nell'iterazione della accept, ma puoi non usarla (forse non è ancora il momento) . Fai una funzione di accept e recv (singola) da richiamare nel ciclo principale della fork lato parent, questo ti evita il blocco. Finito il giro principale lavora sui segnali (il socket era più coerente) e la wait per il pid e lo status del child.
Se hai problemi chiedi, se ho fatto errori di scrittura chiedo scusa, sono sul mobile

ps. ricordati di spezzare il programma, ti aiuta nello svolgimento, lettura e semplifica l'esercizio
mr_simo
Prode Principiante
Messaggi: 59
Iscrizione: giovedì 8 novembre 2012, 12:01
Desktop: ubuntu -2d
Distribuzione: ubuntu 12.04 LTS
Località: Perugia

Re: programmazione di rete con i socket

Messaggio da mr_simo »

no no, non hai fatto nessun errore di scrittura, tranquillo!!ok, grazie del consiglio!! adesso mi metto giù modifico il codice e utilizzo le funzioni, poi una volta fatto ti faccio sapere, grazie di nuovo! :D
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 4 ospiti