PDA

Visualizza la versione completa : [C] Group Chat P2P


skipper87
20-02-2014, 17:42
Salve a tutti,
Il problema è questo: devo realizzare un semplice sistema di chat di gruppo peer-to-peer.
Quindi il sistema deve essere composto da una insieme n di client di chat che insieme formano un gruppo.

Diciamo che saprei gestirmela se fosse una server chat, ovvero il server che gestisce gli utenti. quindi un file server e n file client.

Le comunicazioni averranno tramite l'uso delle socket.

- Il mio problema è che non saprei come inziare :dhò: mi date una spintarella per mettere giù qualcosa?
Correggetemi se sbaglio; nel senso, essendo P2P ogni client deve fare anche da server?

- altra cosa come faccio a creare la chat? ovvero client1 viene generato; genero anche il client2 ma non ho un server da contattare, chi contatto per joinare nella chat? il client1?.

Non voglio la pappa pronta tranquilli, ma solo qualche idea chiara per mettere giù bene le cose.

Grazie a tutti a quelli che mi daranno una mano! :fiore:

Rising1
23-02-2014, 20:15
un po' di tempo fa mi ero interessato pure io alla tecnologia p2p, provo a risponderti sperando di non dire cose sbagliate, infine aggiungo una domanda rivolta a chi è più esperto di me.
generalmente vi è un server che può essere contattato dai vari utenti del servizio di chat.
questo server "traccia" i vari utenti connessi.
una connessione può avvenire in questo modo:

-Utente1 contatta il server centrale, in questo istante si comporta come Client
-il server riceve le informazioni su questo utente (indirizzo ip etc etc) e le salva
-Utente1 chiede al server di rintracciare Utente2
-il server gli invia le informazioni relative all'Utente2, come l'indirizzo ip a cui contattarlo
-la connessione tra l'utente1 e il server può ora momentaneamente chiudersi (ogni tanto si ricollegherà con esso giusto per aggiornare le proprie informazioni e quelle dell'utente2)
-Utente1 chiede di collegarsi all'Utente2. Utente 2 si comporta ora come Server
-La comunicazione può avvenire

in linee generali il tutto avviene così
Naturalmente il server centrale serve perchè i vari utenti molto probabilmente hanno un ip dinamico che quindi li rende impossibili da rintracciare altrimenti.

Ne approfitto allora per fare una mia considerazione: Nel caso di connessioni nattate come le vecchie connessioni fastweb, in cui uno stesso ip viene assegnato ad un gruppo di abitazioni (ad esempio) e poi ogni connessione interna ha un ip "tradotto" dal nat, può funzionare tale sistema P2P? non appena un Utente vuole contattarti, con l'ip che il server gli fornisce è in grado di rintracciarti?
so che questo problema è molto frequente nelle connessioni tcp/ip

vbextreme
24-02-2014, 15:04
No in realtà il server si deve preoccupare di rilasciare un qualsiasi indirizzo ip valido(un qualsiasi ip connesso alla p2p) a prescindere dall'user ricercato.
Una volta ottenuto un ip connesso alla p2p allora ci si connetterà al suddetto ip accedendo alla p2p e si andrà in ricerca dell'user desiderato.
Gestire correttamente le connessioni è la parte piu complessa.
Bisogna fare in modo che anche se un ip "cade" gli altri rimangono "su",quindi ogni ip avrà almeno 2/3 connessioni attive verso la p2p.
Anche gestire l'instradamento corretto dei pacchetti non è cosa semplice,ma se si è riusciti nella fase precedente allora si hanno le capacità per risolvere anche la seconda fase.

skipper87
25-02-2014, 16:30
Ciao! innanzitutto grazie per le risposte.
Allora, ho inziato a fare una parte client e una parte server (perchè più easy).

ora vi chiedo, poi essendo p2p, ogni utente dovrà fare allo stesso tempo sia da client che da server. giusto?
come smisto il rimanere in ascolto? e effettuare un eventuale connessione? devo fare un fork()?
e devo fare un altro fork() per inviare e ricevere messaggi? cioè devo fare un processo che gestisce gli invii e uno che gestisce le ricezioni?

altra cosa che non mi è ben chiara. A->B (A crea una socket e ascolta, e B si connette).
A può inviare messaggi a B... se B vuole mandare messaggi ad A (B->A) deve aprire e farsi accettare una sua socket o può usare la stessa creata per A->B?

Non so se è un bene o un male, ma prevedo di mandare solo messaggi in broadcast, cioè se ci sono 3 utenti tutti vedono tutti i messaggi scambiati tra tutti.

Grazie!

vbextreme
27-02-2014, 21:26
ci sono diverse tecniche per usare socket non bloccati,quello della fork è un tipo.
Per me il piu semplice è col mutithread:
-thread main lancia il thread listen che fa rimanere in ascolto su una porta ed accetta la connessione ricreando un nuovo thread per quel socket e rimanendo in recv
ora hai:
thread main,thread listen,thread n recv
dal main puoi inviare qualsiasi messaggio a qualsiasi socket anche se in recv.
Ci sono anche i socket non bloccati ma sono un pò difficili da usare.Ti conviene comunque leggere i vari tutorial online che spiegano bene come fare.

Una volta stabilita la connessione tra A e B su una porta sei aposto,puoi inviare o ricevere dati.Quindi non c'è bisogno di aprire un canale per l'invio e uno per la ricezione.

skipper87
27-02-2014, 21:51
Ottimo, grazie mille.
Si ho già imbastito le connessioni.. ora devo cercare solo di sistemare e fare i thread..
Li avevo già guardati ma dovrò rifarlo :-p

Mi puoi ricapitolare i tread che secondo te dovrei fare?

Pensavo:
.... Aspetta forse ho capito... Tu dici:
Tread che rimane in ascolta e accetta le connessioni, poi un sotto tread che stabilisce la connessione con questa accettata e ne permette invio e ricezione di messaggi?


Non ho ben Capito: "dal main puoi inviare qualsiasi messaggio a qualsiasi socket anche se in recv."


Altra cosa, per mantenere una lista degli utenti e le loro porte di riferimento, meglio usare una memoria condivisa?

vbextreme
27-02-2014, 22:23
potresti ad esempio usare una lista globale di tutti i socket creati.
Quindi Il thread Listen farà la accept e aggiunge socket alla lista e lancierà nthread con parametro nuovo socket .
Appena sarà avviato questo nuovo thread andrà in recv e gestirà i dati in arrivo e basta.
Ora ad esempio nel main tu avrai accesso alla lista dei socket e quindi potrai effettuare una send a qualsiasi socket presente nella lista.


Non ho ben Capito: "dal main puoi inviare qualsiasi messaggio a qualsiasi socket anche se in recv."
Anche se un thread è in recv quindi bloccato in attesa di dati, tu puoi usare lo stesso il socket da un'altro thread(esempio il main) per effettuare una send.

skipper87
27-02-2014, 22:29
Ora ad esempio nel main tu avrai accesso alla lista dei socket e quindi potrai effettuare una send a qualsiasi socket presente nella lista.

Anche se un thread è in recv quindi bloccato in attesa di dati, tu puoi usare lo stesso il socket da un'altro thread(esempio il main) per effettuare una send.

Ok grazie!
Ma giusto una cosa.
Thread main intendi il main normale del programma giusto? O un altro thread ancora? :)

Grazie per le tue risposte comunque! Sei stato gentilissimo! Già domani vedrò di iniziare a guardare bene ;)

vbextreme
28-02-2014, 09:10
si intendo il task principale.
Ti conviene farti una bella ricerca in internet e iniziare a leggere.
Su windows sono andato molto bene creando un ibrido tra thread e socket non bloccanti.
Su Linux invece son andato ancor meglio solo coi thread.

skipper87
02-03-2014, 11:21
Ciao a tutti, ho un problema con il codice.
allora, andrebbe anche bene da un certo punto di vista, ma no :nonono::D

Allora questo è uno stralcio di codice del server, fa le sue operazioni di bind e listen,
poi entra in un while(true) per fare l'accept e parte un thread.
Il thread ha un while che mi continua a ricevere quello che scrive l'utente (credo :D)



......
//Bind
//Listen
listen(serverfd , 5);
//Accept and incoming connection
c =sizeof(struct sockaddr_in) ;

//thread_id
pthread_t thread_id;

while( (clientfd = accept(serverfd, (struct sockaddr *)&client_addr, (socklen_t*)&c)) ){
puts("Connection accepted");
pthread_create( &thread_id , NULL , connection_handler , (void*) &clientfd);
puts("Handler assigned");
}//while

//Se scrivo qui non me lo legge, rimane nel while
return 0;
}

// funzione thread
void *connection_handler(void *serverfd)
{
int sock = *(int*)serverfd;
char msg[MSG_SIZE];
int read_size;

while( (read_size=recv(sock, msg, MSG_SIZE * sizeof(char), 0)) > 0 ){
printf("%s\n", msg);
bzero(&msg, MSG_SIZE * sizeof(char));
}//while

pthread_exit(NULL); //non sono sicuro serva
return 0;
}


Il codice funziona bene, infatti se apro anche più client poi me li vede entrambi e possono scrivere entrambi.
IL PROBLEMA:
per semplificare intanto cosi è solo il client che scrive e solo server legge.
Ora vorrei fare in modo che il server possa rispondere ai client (tutti possibilmente (ma ci penso anche dopo)) in maniera asincrona.

però cosi facendo non riesco a uscire dal while.. e il mio main resta inutilizzato, non so come poter riusare il main, o fare questa cosa, aprire un altro thread nel thread creato? :bhò: come credo mi avevi suggerito.

Grazie:ciauz:

Loading