Socket tcp , bufferizzare dati ricevuti con recv

di il
7 risposte

Socket tcp , bufferizzare dati ricevuti con recv

Ciao,

connessione client-server TCP
formato del pacchetto che devo inviare
|un intero (lunghezza campo dati) | campo dati |

devo inviare con la send un int il quale rappresenta la lunghezza di una stringa che verrà inviata subito dopo, in maniera che la recv possa sapere quanti byte è lungo il campo dati.

Il mio problema è il buffer dell'intero che non so proprio come farlo e il buffer della stringa ho il dubbio :
se invio la stringa "casa/0" , al ricevitore arriva prima la lettera "c" o la "/0" ?

Questo è il mio codice:
int recvTCP(int sd, void* buf, int len)  
{
	int ret;
	ret = recv(sd,buf,len,0);
	if (ret<len)
	{
		if(ret==0)  //chiusura connessione da parte di un client oppure errore
		{
			//chiusura connessione da parte di un client oppure errore
		 	FD_CLR(sd,&master); //rimuovo la socket dal master set
		 	close(sd); //chiudo la socket
		 	printf("%s si è disconnesso dal server\n",client->username);
		 	if(client->impegnato==YES)  //si è chiuso durante una partita quindi è un problema da notificare all'avversario
		 	{
		 		//notifica(client->enemy->socket);
		 	}
		 	if(client->ready==YES)
		 	{
		 		numerogiocatori--; //ho un giocatore pronto a giocare in meno
		 	}
		 	elem_remove(client); //rimuove l'elemento dalla lista connessi
		 	return -1; //non ritorna nessun byte c'è solo stata una chiusura
		}
		
		return ret; //ritorna il numero di byte letti 
		
	}
	return 0; // tutto ok
}

int riceviLength() //usando lo shift sistemo i byte in host order senza usare la funzione ntohl 
{
   //in realtà inviando un int per la dimensione invio ben 4byte, devo gestire un buffer per la lunghezza
  int ret;
  int temp; //al suo interno ci viene salvato il dato letto
  ret = recvTCP(client->socket,&temp,4-client->last);
  client->length=(client->length)<<(8*(ret)); 
  client->length=(client->length)|temp;  
  if(ret<0) return -1; //c'è stata una chiusura della connessione già gestita dalla recvTCP o il dato è ricevuto correttamente
  if (ret==0)  //abbiamo finito di leggere
  {
  	client->last=0;
  	return 0;
  }
  client->last=client->last-ret;
  return ret;
}

int riceviMsg()
{
	int ret;
	ret = recvTCP(client->socket,&(client->buffer[client->last]),client->length);
	if(ret<0) return -1; //c'è stata una chiusura della connessione
	if(ret==0) 
	{
		client->last=0; //rimetto a 0 la variabile che mi indica dove sono rimasto a leggere
		return 0; //dato completamente ricevuto
	}
	client->last=ret;
	client->length=(client->length)-(client->last);  //aggiorno la lunghezza da leggere all'interno della struttura client
	return ret;
}
La riceviLenght è iper provvisoria e credo di modificarla inviando l'intero convertendolo in una stringa , in maniera da gestire il buffer come con la riceviMsg().

La riceviMsg() viene richiamata dal main nel caso non sia finita la lettura ( lato server ho dovuto far così invece che con il while per evitare di bloccare la select , lato client ho fatto un while direttamente ) .

Il problema della riceviMsg è che ho paura che ricevo la stringa, ma la interpreto nell'ordine di arrivo sbagliato.

Spero possiate darmi una manina

Grazie in anticipo a tutti

7 Risposte

  • Re: Socket tcp , bufferizzare dati ricevuti con recv

    Ovviamente arriva prima la c

    Comunque se ne stava amabilmente parlando in

    http://www.hwupgrade.it/forum/showthread.php?t=2657677&page=4

    ... perché spostarsi in altro forum (in cui, fra l'altro, non è una cosa ben vista ... ?)
  • Re: Socket tcp , bufferizzare dati ricevuti con recv

    Ciao ! Grazie
    Eh si in effetti se ne stava parlando di là, solo che sono andato in paranoia, perchè mi è venuto questo dubbio e di là erano diversi giorni che non ricevevo risposte (è anche normale , mica tutti possono essere sempre connessi e avere sempre voglia di rispondere ) allora ho provato a cercare su altri lidi, e il primo posto che mi è venuto in mente è questo forum dove si parla come argomento principale di programmazione

    Comunque tornando INTOPIC perchè dici naturalmente ? Mi era venuto questo mega dubbio

    Comunque allora la buffer della riceviMsg sembra fatta correttamente. QUindi provvederò a portare su 4byte l'integer e riutilizzo la riceviMsg per controllare il tutto

    Per ricevere un int bufferizzandolo ci sono modalità giuste o è molto più complesso ?
  • Re: Socket tcp , bufferizzare dati ricevuti con recv

    Non fare strane elucubrazioni mentali ...

    se invii: 1234567

    riceverai: 1234567

    c'e' un problema pero':

    1) il sender invia i dati solo quando il buffer di spedizione risulta pieno, oppure quando forzi lo svuotamento con un 'flush', o per timeout

    2) il messaggio non viene inviato in un unico blocco, ma il TCP puo' decidere di spezzarlo in 2 o piu' parti (quindi ti servono 2 o piu' receive per ricostruirlo).
    Ma e' pure peggio di cosi': non c'e' nessuna regola su dove viene fatta la suddivisione, o almeno nessuna regola sotto il controllo del programmatore:

    potrebbe inviare tutto il messaggo, o spezzarlo in due blocchi uguali, oppure inviare un byte alla volta.

    Non lo puoi sapere a priori.

    Quindi, in ricezione devi usare un buffer temporaneo, e attendere di ricevere abbastanza byte prima di proseguire.

    E se invii 2 o piu' messaggi, li potrebbe pure concatenare ...

    Non e' difficile implementare il tutto, ma devi fare parecchia attenzione:

    il diavolo si nasconde nei dettagli



    Ultima nota: la dimensione massima del blocco di dati inviati dal TCP e' di 65520 byte (i rimanenti 16 sono di servizio). Quindi se in ricezione crei un buffer da 2*65536 byte (il 2 lo capirai in fase di implementazione) sarai certo di non avere mai problemi di buffer troppo piccolo.
  • Re: Socket tcp , bufferizzare dati ricevuti con recv

    aeroxr1 ha scritto:


    Comunque tornando INTOPIC
    Non è questione di intopic o no, Il problema è che qui è VIETATO questo tipo di comportamento dal regolamento. Ma è solo per tua informazione ...
    perchè dici naturalmente ?
    Scusa, ma tu hai provato e hai avuto dei problemi di ricezione?
  • Re: Socket tcp , bufferizzare dati ricevuti con recv

    oregon ha scritto:


    Scusa, ma tu hai provato e hai avuto dei problemi di ricezione?
    Sulla ricevi messaggio non ho avuto problemi, ma provandolo su localhost e con pochi dati, invio con tre send : prima 1byte di comando poi 4byte di lunghezza dati poi il dato vero e proprio (un'altra decina di byte) ; non capita quasi mai che mi arrivi il msg < della lunghezza aspettata e così non metto mai alla prova la bufferizzazione.

    Sull'intero il problema è il seguente :
    se io prima di inviare il dato trasformo l'endian del numero con htonl() e lo invio con la send , dal lato client quando arrivo a fare la ricevi e utilizzo la mia funzione di shift il numero ritornato è sbagliato.
    Il numero mi ritornava corretto quando lato client non usavo la htonl() .
    Insomma tornava il numero corretto quando sbagliavo
  • Re: Socket tcp , bufferizzare dati ricevuti con recv

    se io prima di inviare il dato trasformo l'endian del numero con htonl() e lo invio con la sen
    Traduci in linguaggio umano, per favore!

    Che stai a di'?
    A che ti serve usare l'htonl?

    So a che serve, ma a che serve a TE?

    Ragiona!

    Non penserai mica che il protocollo di rete si mette a pasticciare con l'ordine dei byte?

    E che cavolo ne sa lui di che interpretazione deve dare ai byte che deve ricevere o inviare!
  • Re: Socket tcp , bufferizzare dati ricevuti con recv

    Bloccato per crossposting
Devi accedere o registrarti per scrivere nel forum
7 risposte