PDA

Visualizza la versione completa : [C] Client Chat MultiThreaded


Sangio90
17-12-2011, 14:24
ciao a tutti, ho realizzato (tramite le socket) un Server che riceve connessioni da 3 hosts identificandoli come pc1,pc2,pc3 e riceve messaggi da ognuno di loro, inoltrandoli al corretto destinatario. Ora però per realizzare un client che funzioni in tempo reale ho bisogno di un programma in sola ricezione ed uno in sola scrittura (così posso ricevere messaggi anche mentre ho aperta la scanf per scriverne uno).
Fatto questo vorrei far partire entrambi i programmi in un solo click, possibilmente nella stessa finestra, ho visto che esiste la funzione CreateThread, che purtroppo fatico ad utilizzare, avete consigli al riguardo?

oregon
17-12-2011, 15:02
In definitiva vuoi usare i thread.

Non è solo capire come funziona la CreateThread ma come gestire i thread in un programma.

Il consiglio è di fare qualche prova con i thread per capire come funzionano ... ci sono molti esempi su internet ma vanno ovviamente adattati ...

Per cominciare a capire i thread

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx

ma anche questo (seppure datato)

http://www.codeproject.com/KB/IP/winsockintro03.aspx?msg=1471805

e così via ...

Sangio90
17-12-2011, 17:53
comunque quello che voglio fare è possibile confermi?
ps. mi piacerebbe poter usare un parametro (argv[1]) ma dovendo dichiarare il main dopo le dichiarazioni di thread le variabili argv non sono riconosciute, c'è un modo?
grazie

oregon
17-12-2011, 17:57
Originariamente inviato da Sangio90
comunque quello che voglio fare è possibile confermi?

Sì, ma non dovrai utilizzare due programmi, ma un programma con più thread.


ps. mi piacerebbe poter usare un parametro (argv[1]) ma dovendo dichiarare il main dopo le dichiarazioni di thread le variabili argv non sono riconosciute, c'è un modo?


Ma per fare cosa?

Sangio90
17-12-2011, 18:08
il programma client funziona così: lo si avvia e si da come parametro pc1 pc2 o pc3 (è una piccola chat che realizzo per un progetto scolastico), a seconda di questo il programma si connette al server ad una porta diversa.
posto il codice del programma client intero, sapresti illuminarmi su come posso adattarlo?
grazie mille:

(IN QUESTO PEZZO HO SOSTITUITO GLI ARGV CON UNA SCANF (MA E' ORRIBILE E VORREI RITORNARE ALL' ARGV)

CLIENT (PARTE DI INVIO MSG):
{
char buffer[80] = {""};
char dest[10];
char mitt[4]={"pc"};
int miopc;
struct sockaddr_in server;
int sd,status,server_size=sizeof(server);
printf("SEND - Digita pc1,pc2,pc3 a seconda della tua identità:\n");
scanf("%d",&miopc);
if (miopc==1)
mitt[2]='1';
if (miopc==2)
mitt[2]='2';
if (miopc==3)
mitt[2]='3';

// INIZIALIZZAZIONE DELLA STRUTTURA SERVER E CREAZIONE DELLA SOCKET SD CONNESSA AL SERVER(IL CUI IP E' INSERITO MANUALMENTE COME PARAMETRO)

server.sin_family=PF_INET;
server.sin_addr.s_addr=inet_addr("192.168.1.101");
server.sin_port=htons(atoi("4000"));

printf("IP Server : %s , Porta Server : %d !\n",inet_ntoa(server.sin_addr),ntohs(server.sin_port) );
sd=socket(PF_INET,SOCK_STREAM,0);
connect(sd,(struct sockaddr*)&server,sizeof(struct sockaddr_in)); // CONNESSIONE DELLA SOCKET AL SERVER

while(1) { // CICLO "INFINITO" DI INVIO MESSAGGI
printf("Destinatario:\n"); // RICHIESTA DEL DESTINATARIO
scanf("%s",dest);

send(sd,dest,sizeof(dest),0); // INVIO IL DESTINATARIO AL SERVER, COSI SAPRA' A CHI INOLTRARE IL MESSAGGIO
if(strcmp(dest,"quit\0")==0) // SE IL DESTINATARIO ERA QUIT, ALLORA ESCO DAL CICLO E CHIUDO IL PROGRAMMA
break;

printf("Testo:\n"); // RICHIESTA DEL TESTO
getchar();
gets(buffer);
send(sd,mitt,4,0);
send(sd,buffer,sizeof(buffer),0); // INVIO DEL MESSAGGIO

} // FINE DEL CICLO WHILE(1), RICOMINCIO CON UN NUOVO MESSAGGIO
closesocket(sd);
}

CLIENT (PARTE RICEZIONE):

{

char mitt[10];
char buffer[80];
int miopc;
int sd,nsd,addrlen=sizeof(struct sockaddr_in),status,sdpc1,sdpc2,sdpc3;
struct sockaddr_in pc,server;
printf("READ - Digita pc1,pc2,pc3 a seconda della tua identità:\n");
scanf("%d",&miopc);
server.sin_family=PF_INET;
server.sin_addr.s_addr=inet_addr("192.168.1.101");
server.sin_port=htons(atoi("4000"));

sd=socket(PF_INET,SOCK_STREAM,0);
status = bind(sd,(struct sockaddr*)&server,addrlen);
connect(sd,(struct sockaddr*)&server,addrlen);

if(miopc==1){

pc.sin_family=PF_INET;
pc.sin_addr.s_addr=inet_addr("192.168.1.101");
pc.sin_port=htons(atoi("5001"));
sdpc1 = socket(PF_INET,SOCK_STREAM,0);
bind (sdpc1,(struct sockaddr*)&pc,addrlen);
listen(sdpc1,10);

while(1) {
nsd = accept(sdpc1,(struct sockaddr*)&pc,&addrlen);
recv(nsd,mitt,10,0);
recv(nsd,buffer,80,0);
printf("%s : ",mitt);
printf("%s\n",buffer);
closesocket(nsd);
}
}
if(miopc==2){

pc.sin_family=PF_INET;
pc.sin_addr.s_addr=inet_addr("192.168.1.100");
pc.sin_port=htons(atoi("5002"));
sdpc1 = socket(PF_INET,SOCK_STREAM,0);
bind (sdpc1,(struct sockaddr*)&pc,addrlen);
listen(sdpc1,10);

while(1) {
nsd = accept(sdpc1,(struct sockaddr*)&pc,&addrlen);
recv(nsd,mitt,10,0);
recv(nsd,buffer,80,0);
printf("%s : ",mitt);
printf("%s\n",buffer);
closesocket(nsd);
}
}

if(miopc==3){

pc.sin_family=PF_INET;
pc.sin_addr.s_addr=inet_addr("172.25.14.33");
pc.sin_port=htons(atoi("5003"));
sdpc3 = socket(PF_INET,SOCK_STREAM,0);
bind (sdpc3,(struct sockaddr*)&pc,addrlen);
}


GRAZIE MIILLE

oregon
17-12-2011, 18:14
Non posso sicuramente riscrivere il tuo programma con i thread in un post di un forum !

Ma ti posso dare alcuni consigli e, per primo, il fatto che i tuoi client devono collegarsi tutti alla stessa porta del tuo server e non a porte diverse.

Sangio90
17-12-2011, 18:42
ci avevo pensato, ma come distinguo i vari pc? ad esempio come so(una volta che sia pc1 che pc2 sono connessi) da chi dei due arriva il messaggio?
se faccio la accept ad ogni richiesta ho visto che crea una socket sd2 che ogni volta ha un id diverso, ma se chiamo sd2 questa avrà sempre il valore dell' ultimo utente connesso, non dell' effettivo utente.
purtroppo la select mi crea qualche difficoltà.. grazie

oregon
17-12-2011, 18:58
Distinguere i PC per quale motivo?

Importante memorizzare il descriptor restituito dalla accept in un array.
In questo array avrai tutte le connessioni attive per poter redirigere le comunicazioni.

Se ti serve una "descrizione" del pc collegato (o un utente, un nick), lo invierai come prima stringa subito dopo la connessione e lo memorizzerai in un array parallelo a quello delle connessioni.

In realtà bisogna che tu prenda ancora maggiore confidenza con le nozioni di programmazione di rete di base necessarie.

Ti consiglio di leggere con attenzione il gapil (Parte II) ...

http://www.lilik.it/~mirko/gapil/gapilpa2.html#x545-257000II

Sangio90
18-12-2011, 14:37
ok, avevi ragione! tutto fatto!!
Ora il server ascolta sulla porta 4000 e gestisce tutto, usando degli array paralleli ho salvato ID / SOCKET di ciascun pc connesso e così son riuscito a farli comunicare!
Ora tornerei al mio dubbio precedente, dato questo sistema, come posso gestire il multithreading del client?
NON con un timer, rischierei di interrompere l' utente che scrive il messaggio e non permetterei di scrivere quando vuole..
Vorrei poter essere sempre in client_send(in gets() per messaggi da inviare), e se arrivano messaggi vorrei che quel thread venisse sospeso per passare alla recv, e poi ripreso.
è possibile?

oregon
18-12-2011, 14:51
Prova a separare la parte di invio e quella di ricezione in modo che vengano eseguiti in due thread separati.

Lascia la parte di invio nel thread principale (quello automaticamente creato quando parte il processo) e la ricezione in un secondo thread appositamente creato dopo la creazione della connessione.

Ovviamente, per i dettagli della gestione del thread (creazione, distruzione ...) dovrai studiare un po' prima, magari facendo esperienza con programmi più semplici ...

Loading