Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Medir cadena con un /0 por medio

Estas en el tema de Medir cadena con un /0 por medio en el foro de C/C++ en Foros del Web. Muy buenas, Estoy haciendo una practica cliente /servidor en c ara uni usando sockets. Para empezar tengo que enviar un "codigo + Hello World" del ...
  #1 (permalink)  
Antiguo 09/03/2013, 05:37
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 8 años, 6 meses
Puntos: 0
Medir cadena con un /0 por medio

Muy buenas,

Estoy haciendo una practica cliente /servidor en c ara uni usando sockets.

Para empezar tengo que enviar un "codigo + Hello World" del servidor al cliente, esto me funciona bien, pero hay una cosa que no me acava de convencer.

Cuando hago el sendto:
Código:
stshort(2,buffer);
            t_short=sizeof(short);
            strcpy(buffer+t_short,"HELLO WORLD");
            tamany_buffer=t_short+strlen(buffer+1);
            
            sendto(sockServer, buffer, tamany_buffer, 0, (struct sockaddr*)&server, sizeof(struct sockaddr_in));
en tamany buffer es igual al numero de caracteres que envio en este caso 14 hasta aqui todo perfecto luego en el cliente cuando recibo los datos con:
Código:
bytes_rebuts= recvfrom(sockClient, buffer, strlen(buffer), 0, (struct sockaddr*)&client, &client_t);
En el 3er campo de la funcion tengo que medir los caracteres recividos, lo que pasa que no se como recivir los bytes exactos, ya que si hago un strlen el valor que retorna es 0 ya que el mensaje que envio es /0/2He.. entonces no me lee mas alla del /0.

He probado en hacer un sizeof(buffer) lo que pasa que me mide el tamaño total de la variable, en este cas 2000 porque la tengo declarada asi.

Como puede poner que envie 14 caraceres i reciva 14?

Saludos
  #2 (permalink)  
Antiguo 09/03/2013, 05:58
 
Fecha de Ingreso: julio-2012
Mensajes: 375
Antigüedad: 8 años, 10 meses
Puntos: 28
Respuesta: Medir cadena con un /0 por medio

Puedes hacer que el servidor te diga de antemano los caracteres que te va a enviar.

O bien incoporar todo en una misma estructura.
  #3 (permalink)  
Antiguo 09/03/2013, 06:59
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 8 años, 6 meses
Puntos: 0
Respuesta: Medir cadena con un /0 por medio

Si es que con el comando strace puedo ver lo que envio y en el send to envia 14 pero en el recibe no se como poner que reciva solo lo que envio.
  #4 (permalink)  
Antiguo 09/03/2013, 08:24
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 8 años, 8 meses
Puntos: 83
Respuesta: Medir cadena con un /0 por medio

'strlen' es una funcion que sirve para contar caracteres hasta que encuentra el caracter nulo, está dirigida al trabajo con texto plano y no puedes cambiarlo, y tal como has comprovado no te sirve.

Para trabajar con datagrams tienes que serializar el envio, de lo contrario nunca podras separar los datos en caso que haya datos combinados como el que planteas:

Código:
numerico de 2 bytes
texto de x bytes

buffer[byte 1 y byte 2] = entero de 2 bytes
buffer[byte 3 ... byte x] = texto de x bytes

longitud a enviar = 2 bytes + x bytes
Ten en cuenta que para el envio el caracter de final de cadena \0 que pones al final de 'hola mundo' no es necesario, solo es cuestion de saber que cuando lo recibes debes guardarlo en un buffer del tamaño de texto recibido +1, pero esto no es importante.

Si el texto a enviar contiene \0 como una lista de textos, deberas implementar tu propia funcion para calcular la longitud exacta de todo el bloque; normalmente en estos casos se usa el doble nulo como indicador de final de bloque; un ejemplo de como harias la funcion para serializar el envio de ese caso concreto:

Código:
/**
la funcion espera un codigo y un texto
*/
void envia(short codi, char *texte) {
	char buffer[1024];
	int lon_texte, tamany_buffer, rb;
	short num_rec;
	unsigned short nbo;
	
        //conviertes a network byte order y lo clavas en el buffer
	nbo = htons(codi);
	memcpy(buffer, &nbo, sizeof(unsigned short));
	
        //calculas la longitud del texto
	rb = 0;
	lon_texte = 0;
	while(strlen(texte + rb) > 0) {
		lon_texte += strlen(texte + rb) + 1;
		rb += (strlen(texte + rb) + 1);
	}
        
        //concatenas el texto
	memcpy(buffer+sizeof(unsigned short), texte, lon_texte);

        //calculas tamaño de buffer de salida
        tamany_buffer = sizeof(unsigned short) + lon_texte;

        //finalmente lo envias con sendto o como sea
}

//haces la llamada a la funcion
envia(2, "una\0prova\0de\0texte\0");

//otra llamada de ejemplo para comprovar que tambien funciona con texto plano
envia(2, "esto funciona\0");
Tal como ves el texto puede contener cuantos nulos quieras, el truco está en crear tu propio sistema de trabajo: en este caso requiero que las cadenas de texto siempre finalicen con un nulo extra, y eso me permite insertar aun mas nulos dentro del texto (esto es habitual en listas de textos). Si no necesitas enviar nulos dentro del texto con el strlen tienes suficiente para calcular la longitud del texto para el buffer de salida.

Ahora lo que te interesa: como separas lo que recibes? Esta es la descripcion del valor de retorno de la funcion (en ingles, pero se entiende)

Código:
Return Values

If no error occurs, recvfrom returns the number of bytes received. If the connection has been gracefully closed, 
the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be 
retrieved by calling WSAGetLastError.
Eso significa que si recibes 0 es que todo està dentro del buffer de entrada y la conexion ha finalizado correctamente; si recibes -1 (SOCKET_ERROR) es que se produjo un error; y si recibes el nº bytes igual al tamaño del buffer de entrada es que como minimo aun queda otro paquete por recibir, en ese caso guardas en otro buffer y concatenas los siguientes paquetes hasta recibir el final de conexion. Lo que necesitas es llegar a un retorno de 0 (puede ser en la primera lectura o en la 14, da igual)

Nota: es importante que antes de cada recvfrom reinicies todo el buffer de entrada a nulo (y no vale buffer[0] = 0), de lo contrario te quedaran datos basura que no podras distinguir de los datos recibidos ok?

Una vez tienes el buffer de datos recibidos de longitud incierta sabes el tamaño del buffer pero no los bytes utiles, ahora entra en juego la serializacion del envio: 2 bytes numerico + x bytes de texto; primero sacas el numero y luego haces lo mismo que en la funcion de enviar pero comenzando a contar en rb = sizeof(unsigned short)

Código:
void reb() {
        char buffer[1024];
	int rb, lon_texte;
	unsigned short nbo;
	short num_rec;

        //reseteo el buffer, muy importante
        memset(buffer, 0, sizeof(buffer));	
    
        //me salto las comprovaciones e imagino que a la primera recibo todo
        recvfrom(sockClient, buffer, sizeof(buffer), 0, (struct sockaddr*)&client, &client_t);
	
        //aqui se supone que recvfrom ha retornado 0 para finalizar la conexion y todo
        //ha ido sin errores, la utopia del programador :)

        //aplicas la des-serializacion

        //extraes el numero
	memcpy(&nbo, buffer, sizeof(unsigned short));
	num_rec = ntohs(nbo);
	
        //calculas el tamaño de texto
	rb = sizeof(unsigned short);
	lon_texte = 0;
	while(strlen(buffer + rb) > 0) {
		lon_texte += strlen(buffer + rb) + 1;
		rb += (strlen(buffer + rb) + 1);
	}
	
	//ya tienes lon_texte que es la longitud del texto, lo extraes del buffer con un offset de 2 bytes
        memcpy(buffer_destino_texto, buffer, sizeof(unsigned short));
}
La cosa funciona porque el bufer esta iniciado a nulo, y el texto recibido termina en nulo: para esta serializacion es indispensable que el texto a enviar termine en nulo y que ademas el nulo final se compute como byte a enviar y por lo tanto como byte a recibir, por eso puedes aplicar la desserializacion a los datos recibidos

Otra cosa, eso de stshort me he imaginado que estas convertiendo a network byte order, para ello he usado htons para el envio y ntohs para el recibo.

Mas cosas, echa un vistazo a la funcion recvfrom que has colgado, el tercer argumento es el tamaño disponible (ojo, tu has puesto la longitud de texto) y debes indicar sizeof(buffer), o en caso de concatenar paquetes recibidos será el tamaño de buffer no ocupado.


"...Para empezar tengo que enviar un "codigo + Hello World" del servidor al cliente, esto me funciona bien, pero hay una cosa que no me acava de convencer...."

'acava' va con b :)

Saludos
vosk

Etiquetas: cadena, funcion, medio, medir, variable
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 07:22.