Formattazione testo per il networking

di il
6 risposte

Formattazione testo per il networking

Salve,
mentre cercavo di inviare una stringa da un client ad un server mi sono accorto che questa arriva al server in modo "frammentario",ovvero arrivano intere solo le parole senza spazi,mentre le frasi vengono spezzate,se ad esempio invio al server

\\altro codice
while (true)
{
        recv(connSock,buf,sizeBuf,0);
	cout << buf << endl;
}
una strina del tipo "Hello",questa mi viene mostrata come "Hello",ma se invio invece una frase come "Hello World" questa mi viene mostrata come:
-Hello
-World
Adesso mi servirebbe sapere come posso fare per far stampare a schermo dal server un intera frase inviata dal client senza che questa venga spezzata.
Grazie in anticipo

6 Risposte

  • Re: Formattazione testo per il networking

    La separazione specificatamente sullo spazio e' molto strana.

    Bisognerebbe vedere il codice dell'altro lato.

    Comunque c'e' un assioma che devi conoscere: una connessione TCP e' di tipo stream -> sequenza contingua di byte.

    Non c'e da nessuna parte il concetto di record o messaggio, inteso come: in invio N byte, ricevo N byte.

    Se e' capitato, e' capitato per caso, o piu' specificatamente, per una miracolosa congiunzione degli astri ...

    Ovviamente, non puoi pensare di inviare 1TB di dati in un'unico blocco: il protocollo TCP prevede l'invio di blocchi di byte che devono essere ricevuti e riconcatenati.

    La dimensione di questi blocchi e' un parametro che dipende dalla scheda di rete, dalle configurazioni sul TCP/IP in Windows. Si possono modificare, ma servono per ottimizzazioni lato sistemistico. L'utilizzatore della socket non ha nessuna necessita' di dover agire su tali parametri.

    Anzi, piu' draconianamente, non deve proprio farlo.

    Generalmente il sistema funziona cosi': tu fai la send di un certo numero di byte
    - questi vengono concatenati nel buffer del driver della scheda di rete (o da qualche altra parte, comunque sempre lato S.O.)
    - quando il buffer risulta pieno, viene inviato
    - quando forzi la send, il buffer viene inviato
    - quando scade il timeout, il buffer viene inviato

    Se vuoi implementare il concetto di 'invio di un messaggio di N byte', lo devi implementare specificatamente.

    Il modo e' semplice:

    lato invio:
    - invii la lunghezza del messaggio
    - invii il messaggio di lunghezza data
    - devi prevedere una lunghezza massima per il messaggio (generalmente 32KB sono piu' che sufficienti)

    lato ricezione:
    - ricevi la lunghezza del messaggio
    - ricevi il messaggio di lunghezza data
    - devi prevedere una lunghezza massima per il messaggio (generalmente 32KB sono piu' che sufficienti)

    Questo concettualmente, perche' in realta', poiche' non hai controllo su come il TCP ha spezzato lo stream in invio, devi fare qualcosa del tipo:

    - inizializzi un buffer di servizio con la dimensione massima almeno il doppio della dimensione massima del messaggio che vuoi inviare (64KB)
    - ricevi il buffer e lo concateni con il corrente contenuto del buffer di servizio (1)
    - se ci sono abbastanza byte per la lunghezza del messaggio, leggi tale lunghezza, altrimenti ritorni a (1) [2]
    - se ci sono abbastanza byte per il messaggio, leggi il messaggio, altrimenti ritorni a (1)
    - scarti i byte relativi al messaggio appena letto, ovviamente non gettti quelli rimanenti perche' fanno parte del messaggio successivo, e vai a [2]
  • Re: Formattazione testo per il networking

    @migliorabile
    Inanzitutto grazie della risposta che è incredibilmente dettagliata.
    Io ho delle conoscenze di architettura network ma non riesco a spiegarmi la suddivisione del messaggio quando ci sono gli spazi. Speravo di non dover scrivere una libreria per l'invio di testo,puntando magari su qualche tipo di FLAGS per la funzione recv() (o anche qualche flags per ioctlsock() o sockopt()) che ne cambiava il comportamento in uno del tipo:
    while (finchè non ricevi tutto il messaggio)
    {
    	recv([...],buffer,[...]);
    	buffer += buffer; // aggiungo al buffer tutto il testo
    
    	
    	if(ricezione finita)//esco dal ciclo quando finisce la ricezione dell'intero messaggio
    		break;
    }
    printf("%s\n",buffer); // mostro il messaggio completo
    Grazie dell'aiuto : )
  • Re: Formattazione testo per il networking

    Ovviamente non esiste nessun flag del genere

    C'e' una possibilita' alternativa: invece del TCP, puoi utilizzare l'UDP.

    Il protocollo UDP e' la base del TCP, ha diversi pregi e qualche diffetto.

    Il pregio e' che implementa nativamente il concetto di messaggio

    Il diffetto e' che un pachetto UDP si potrebbe anche perdere: non tanto perche' viene perso dalla rete, ma perche se ne arrivano tre in tempi molto stretti e il primo non viene processato abbastanza velocemente, il secondo, che viene messo in un buffet in attesa di essere processato, verrebbe sovvrascitto del terzo

    Poi ci sarebbe il PGM ma e' un protocollo molto poco conosciuto e molto specialistico
  • Re: Formattazione testo per il networking

    Ok,quindi sostanzialmente devo creare da zero la libreria per gestirlo.
    Seguirò i consigli che mi hai dato nel primo commento, Grazie mille per l'aiuto : ).
  • Re: Formattazione testo per il networking

    Ho tirato fuori questi 2 algoritmi per l'invio e la ricezione dei messaggi,ma il problema è che arrivano sempre spezzati ad ogni spazio.
    per la ricezione:
    int recvMsg(SOCKET s,char * recvBuf,int length)
    {
    	int result = 0,
    		i = 0,
    		posix = 0;
    	char tempBuffer [MAX_BUFFER_LENGTH];
    	char temporanyBuffer[REMAINS_BUFFER_LENGTH];
    	ZeroMemory(&tempBuffer,MAX_BUFFER_LENGTH);
    	ZeroMemory(&temporanyBuffer,REMAINS_BUFFER_LENGTH);
    	
    	result = recv(s,tempBuffer,MAX_BUFFER_LENGTH,0);
    
    	if(result < 0)
    		return result;
    
    
    	
    	while(true)
    	{
    		if(tempBuffer[i] == '\0')
    		{
    			strcpy(recvBuf,tempBuffer);
    			ZeroMemory(&recvBuf,sizeof(recvBuf));
    			break;
    		}else if(tempBuffer[i] != '\0' && i == strlen(tempBuffer))
    		{
    			result = recv(s,temporanyBuffer,REMAINS_BUFFER_LENGTH,0);
    			if(check_if_null_terminated(temporanyBuffer))
    			{
    				strcpy(recvBuf,temporanyBuffer);
    				ZeroMemory(&temporanyBuffer,REMAINS_BUFFER_LENGTH);
    				break;
    			}else
    			{
    				posix = check_position_of_string(temporanyBuffer,tempBuffer);
    				strcat(tempBuffer,return_substring(posix,temporanyBuffer));
    				i++;
    			}
    			continue;
    		}
    		
    		i++;
    	}
    	
    }
    
    	
    int check_if_null_terminated(char* str1)
    {
    	int i = 0;
    	while(true)
    	{
    		if(str1[i] == '\0')
    		{
    			return 1;
    		}else
    			return 0;
    	}
    }
    int check_position_of_string(char * stringToCompare,char * comparingString)
    {
    	int i = 0;
    	while(true)
    	{
    		if(stringToCompare[i] == comparingString[i])
    			continue;
    		else if(stringToCompare[i] != comparingString[i])
    		{
    			return i;
    			break;
    		}
    	}
    }
    char * return_substring(int posix,char * string1)
    {
    	string str1(string1);
    	int difference = strlen(string1) - posix;
    	string container = str1.substr(posix,difference);
    	char * conversion = const_cast <char *>(container.c_str());
    	return conversion;
    }
    
    per l'invio:
    int sendMsg(SOCKET s,char * sendBuf,int length)
    {
    	int len = strlen(sendBuf);
    	int byte_sent = send(s,sendBuf,len,0);
    	do
    	{
    		if(byte_sent < 0)
    			return byte_sent;
    		else if(byte_sent == len)
    			return 0;
    		else if(byte_sent < len)
    		{
    			char temporanyBuffer[RESEND_BUFFER_LENGTH];
    			ZeroMemory(&temporanyBuffer,RESEND_BUFFER_LENGTH);
    			strcpy(temporanyBuffer,retrive_posix(sendBuf,byte_sent));
    			len = strlen(temporanyBuffer);
    			byte_sent = send(s,temporanyBuffer,len,0);
    		}
    	}while (byte_sent > 0);
    }
    char * retrive_posix(char * sendBuf,int byte_sent)
    {
    	string sendStr(sendBuf);
    	return const_cast<char *>(sendStr.substr(byte_sent,strlen(sendBuf) - byte_sent).c_str());
    }
    Però ho cercato su internet e a quanto ho visto pochi hanno avuto il mio stesso problema,molti usano le funzioni recv() e send() senza verificare che il messaggio arrivi intero.
    MI chiedo perchè a me il messaggio venga spezzato proprio fra gli spazi, e non in qualche altra parte (come sarebbe più logico dato che uso lo stream_socket).
  • Re: Formattazione testo per il networking

    Up
    non riesco a capire dove l'algoritmo sia sbagliato.
Devi accedere o registrarti per scrivere nel forum
6 risposte