Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 14
  1. #1
    Utente di HTML.it
    Registrato dal
    Mar 2001
    Messaggi
    117

    [C/C++ - Linux] Inviare dati "complessi" su un socket

    Salve.
    Ho due semplici programmi che comunicano tramite un socket TCP. I programmi sono scritti in C++ (ma sostituendo i cout e cin con istruzioni printf e scanf possono senza problemi essere ricondotti al C) e vengono eseguiti sotto Linux. Eccoli:

    client.cpp
    codice:
    #include <iostream>
    #include <stdlib.h>
    #include <strings.h>
    #include <sys/socket.h>
    #include <netdb.h>
    
    #define PORT 30000
    
    using namespace std;
    
    
    struct Data
    {
    	int n;
    	int* v;
    };
    
    
    
    int main(int argc,char *argv[])
    {
    	char *host;
    	struct hostent *hp;
    	struct sockaddr_in sin;
    	int sock;
    	Data d;
    
    	if (argc==2)
    	{
    		host=argv[1];
    	}
    	else
    	{
    		cout << "usage: client iphost" << endl;
    		exit(1);
    	}
    
    	hp=gethostbyname(host);
    	if (!hp)
    	{
    		cout << "client: errore host" << endl;
    		exit(1);
    	}
    
    	bzero((char *)&sin,sizeof(sin));
    	sin.sin_family=AF_INET;
    	bcopy(hp->h_addr,(char *)&sin.sin_addr,hp->h_length);
    	sin.sin_port=htons(PORT);
    
    	if ((sock=socket(PF_INET,SOCK_STREAM,0))<0)
    	{
    		cout << "client: errore socket" << endl;
    		exit(1);
    	}
    	
    	if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) <0)
    	{
    		cout << "client: errore connect" << endl;
    		close(sock);
    		exit(1);
    	}
    
    	while(1)
    	{
    		cout << "Quanti elementi vuoi inserire?" << endl;
    		cin  >> d.n;
    		d.v=new int[d.n];
    		for (int i=0;i<d.n;i++)
    			cin >> d.v[i];
    		send(sock,&d,sizeof(d),0);   //ATTENZIONE: ERRORE! La variabile d contiene il puntatore d.v ma non il vettore in heap!!!
    	}
    
    	close(sock);
    
    	return 0;
    }

    server.cpp
    codice:
    #include <iostream>
    #include <stdlib.h>
    #include <strings.h>
    #include <sys/socket.h>
    #include <netdb.h>
    
    #define PORT 30000
    
    using namespace std;
    
    
    struct Data
    {
    	int n;
    	int* v;
    };
    
    
    
    int main()
    {
    	struct sockaddr_in sin;
    	int sock,newsock;
    	int len;
    	Data d;
    
    	bzero((char*)&sin,sizeof(sin));
    	sin.sin_family=AF_INET;
    	sin.sin_addr.s_addr=INADDR_ANY;
    	sin.sin_port=htons(PORT);
    
    	if ((sock=socket(PF_INET,SOCK_STREAM,0))<0)
    	{
    		cout << "server: errore socket" << endl;
    		exit(1);
    	}
    
    	if (bind(sock,(struct sockaddr*)&sin,sizeof(sin))<0)
    	{
    		cout << "server: errore bind" << endl;
    		exit(1);
    	}
    	listen(sock,5);
    
    	while (1)
    	{
    		if ((newsock=accept(sock,(struct sockaddr *)&sin,(socklen_t *)&len))<0)
    		{
    			cout << "server: errore accept" << endl;
    			exit(1);
    		}
    
    		while (len=recv(newsock,&d,sizeof(d),0))
    		{
    			for (int i=0;i<d.n;i++)
    				cout << d.v[i] << " ";		//ATTENZIONE: ERRORE!
    			cout << endl;
    		}
    		close(newsock);
    	}
    
    	return 0;
    }

    Il mio scopo sarebbe inviare una variabile strutturata di tipo Data (compreso il vettore di interi). I programmi, ovviamente, non funzionano come si desidererebbe, in quanto il tipo strutturato Data contiene un puntatore a intero e inviando una variabile strutturata di tale tipo si invia solo il puntatore d.v ma non il vettore puntato. Il tutto sarebbe risolvibile utilizzando per d.v un vettore classico anziché un vettore allocato in heap, tuttavia non essendo nota a priori la lunghezza vorrei evitare di inviare una marea di dati inutili mettendo array a dimensione prefissata.

    Vengo quindi al mio primo quesito: esiste un modo per inviare una struttura dati che contiene un puntatore, ed inviare, quindi, anche i dati puntati? :master:


    Ho poi da porre un'altro quesito, ma un po' collegato all'esempio che ho fatto. In realtà io più che inviare una variabili strutturate con dati allocati in heap (come il tipo Data dell'esempio) necessiterei di inviare array di variabili di questo tipo, e mi farebbe comodo usare gli stl container messi a disposizione dal C++ (mi riferisco, ad esempio, a classi come vector, set e map). Esiste un modo per inviare dati di questo tipo? :master: (se non fosse possibile vedrò di arrangiarmi con un array normale, ma devo comunque risolvere il primo dubbio sui dati allocati dinamicamente)


    Grazie.

  2. #2
    Utente di HTML.it
    Registrato dal
    Jul 2010
    Messaggi
    466
    Premesso che non sono molto ferrato con il C++ (preferisco il C ) e che non ho potuto provare il programma, può essere perchè è un puntatore a cui non viene allocata la memoria e gestito nella maniera corretta?
    Chiedo scusa se mi sbaglio..

  3. #3
    Utente di HTML.it
    Registrato dal
    Mar 2001
    Messaggi
    117
    In sintesi il problema è questo. Supponiamo che io abbia una variabile d di questo tipo:
    codice:
    struct Data
    {
    	int n;
    	int* v;
    };
    Supponiamo che io allochi v dinamicamente (se non ti piace farlo con new perché è del C++ puoi pensare alla malloc) e che io inserisca alcuni valori nel nuovo vettore in heap, puntato da v. Vorrei inviare la variabile d che contiene d.n e d.v. Ovviamente di d.v vorrei inviare tutti i valori interi contenuti nell'heap. Se invece nella send invio brutalmente la variabile d, i valori nel vettore v non saranno inviati, ma sarà inviato il puntatore d.v (che in un altro processo è totalmente inutilizzabile).


    Quando in ricezione leggo, sicuramente faccio un errore perché leggo da un vettore non allocato, ma il reale problema è che i valori del vettore v non vengono inviati proprio. Volevo sapere quindi se c'è un modo elegante per inviare tutto ciò che mi interessa della variabile strutturata.


    P.S. Se preferisci ti traduco l'esempio in C, ma sono più ferrato col C++. In ogni caso, la soluzione (almeno per il mio primo quesito, il secondo è specifico del C++) dovrebbe essere la stessa, sia che si tratti di C che di C++.

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Non puoi. Non nella maniera in cui intendi almeno. E questo vale per ogni dato che sia diverso da un tipo elementare C, una struct contenente puntatori, o tipi C++ (string, vector etc).
    Un modo elegante ci sarebbe, ma richiede un pò di lavoro in più.

    http://www.parashift.com/c++-faq-lit...alization.html
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  5. #5
    Utente di HTML.it
    Registrato dal
    Jul 2010
    Messaggi
    466
    Originariamente inviato da Cell
    Supponiamo che io allochi v dinamicamente (se non ti piace farlo con new perché è del C++ puoi pensare alla malloc)

    P.S. Se preferisci ti traduco l'esempio in C, ma sono più ferrato col C++.
    Beh proprio così no dai, mi riferivo appunto al quel " = new int".
    Se non puoi inviare direttamente il dato della struttura, puoi copiarlo in un puntatore int che immagino allocherai nella maniera corretta ed inviare quello.. Infine, perchè complicarsi la vita?
    Correggimi se sbaglio :master: (o il problema si complica proprio per via dell' heap..)

  6. #6
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Originariamente inviato da shodan
    Un modo elegante ci sarebbe, ma richiede un pò di lavoro in più.

    http://www.parashift.com/c++-faq-lit...alization.html
    [ot]Ah ecco, mi sembrava strano che Java avesse inventato qualcosa di nuovo![/ot]

    Cell se non vuoi ricorrere alla serializzazione, basta aggiungere più banalmente un livello di astrazione alla funzione send() (e, specularmente, a recv())... tradotto, definisci tu una funzione my_send() con la quale inviare prima il campo n e poi i dati all'indirizzo del campo v, e poi richiami questa funzione in main() passandole la struct che vuoi inviare. L'effetto sarà quello di avere una funzione con la quale trasmettere dati strutturati sulla socket.

    Ovviamente il problema è quello che avevi individuato tu fin dall'inizio: il puntatore v (o meglio, l'indirizzo che contiene) ha un senso soltanto all'interno dello spazio di indirizzamento del processo sulla macchina mittente, ma su quella ricevente sarà solo un valore senza senso (e anzi se lo dereferenzi non è escluso che tu possa avere segmentation faults).
    every day above ground is a good one

  7. #7
    A livello un po' più avanzato c'è Boost.Serialization.
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #8
    Utente di HTML.it
    Registrato dal
    Jul 2010
    Messaggi
    466
    Originariamente inviato da YuYevon
    Cell se non vuoi ricorrere alla serializzazione, basta aggiungere più banalmente un livello di astrazione alla funzione send() (e, specularmente, a recv())... tradotto, definisci tu una funzione my_send() con la quale inviare prima il campo n e poi i dati all'indirizzo del campo v, e poi richiami questa funzione in main() passandole la struct che vuoi inviare. L'effetto sarà quello di avere una funzione con la quale trasmettere dati strutturati sulla socket.
    Ok io ho detto una c*giusto? In tal caso abbiate pazienza, non ho sempre molto a che fare con questi argomenti..

  9. #9
    Utente di HTML.it
    Registrato dal
    May 2008
    Messaggi
    475
    Ma si non mi sembra così difficile, si può andare con una serializzazione molto ingenua, senza andare a tirare fuori grandi robe.

    codice:
    struct Data
    {
    	int n;
    	int* v;
    };
    Quindi, dal mittente invii un intero. Il ricevente legge un intero, alloca una struttura Data e riempie il campo n con l'intero che ha letto, lasciando il puntatore indefinito o al massimo a NULL.

    Il mittente invia un altro intero che è il numero di interi nell'array. Il ricevente alloca un array di x elementi e assegna l'indirizzo dell'array al puntatore v della struttura.

    Il mittente invia gli x elementi dell'array. Il ricevente li legge e li inserisce in ordine nell'array allocato.

    Et voilà
    "Let him who has understanding reckon the number of the beast, for it is a human number.
    Its number is rw-rw-rw-."

  10. #10
    Utente di HTML.it
    Registrato dal
    Mar 2001
    Messaggi
    117
    Originariamente inviato da Ippo343
    Ma si non mi sembra così difficile, si può andare con una serializzazione molto ingenua, senza andare a tirare fuori grandi robe.

    [...]

    Quindi, dal mittente invii un intero. Il ricevente legge un intero, alloca una struttura Data e riempie il campo n con l'intero che ha letto, lasciando il puntatore indefinito o al massimo a NULL.

    Il mittente invia un altro intero che è il numero di interi nell'array. Il ricevente alloca un array di x elementi e assegna l'indirizzo dell'array al puntatore v della struttura.

    Il mittente invia gli x elementi dell'array. Il ricevente li legge e li inserisce in ordine nell'array allocato.

    Et voilà
    Va bè... sì, si può fare anche così, ma quello comunque che vi ho riportato è un esempio semplice. In realtà io dovrei inviare delle strutture molto più complesse e, come vi dicevo, mi interesserebbe inviare degli array di strutture, per cui così facendo diventerebbe laborioso. Cercavo appunto una soluzione per poter inviare tutto in un unica send (e ricevere tutto in un'unica receive) utilizzando dei buffer più grandi che possano contenere i dati.

    Originariamente inviato da MItaly
    A livello un po' più avanzato c'è Boost.Serialization.
    Mi avevano già parlato della libreria Boost ma avevo avuto qualche difficoltà a capirla. :master: Dal link che mi hai dato comunque sono riuscito ad accedere anche a qualche altra pagina che la spiegava e pare che io ci abbia capito qualcosina in più.
    Questa va bene sia per inviare strutture con puntatori, sia per inviare stl container, vero?

    Originariamente inviato da shodan
    Non puoi. Non nella maniera in cui intendi almeno. E questo vale per ogni dato che sia diverso da un tipo elementare C, una struct contenente puntatori, o tipi C++ (string, vector etc).
    Un modo elegante ci sarebbe, ma richiede un pò di lavoro in più.

    http://www.parashift.com/c++-faq-lit...alization.html
    Più tardi mi leggo anche questo, grazie.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.