Socket send and recv problema

Iniciado por <<<-Basura->>>, 28 Junio 2013, 06:36 AM

0 Miembros y 1 Visitante están viendo este tema.

<<<-Basura->>>

Tengo un problema con los socket cuando envió y recibo, esto es porque tengo punteros en la clase que estoy enviando, entonces al recibirla me da error de:  Segmentation fault;

esta es la situación que tengo:

Clase a enviar:
Código (cpp) [Seleccionar]

#define TAMANO_MENSAJE 50

class Mensaje {
private:
//char mensaje[TAMANO_MENSAJE];
string mensaje;
public:
Mensaje();
Mensaje(char);
string getMensaje(){return mensaje;}
};



Esta es la función que envía:
Código (cpp) [Seleccionar]

int Sender::SendMensaje(Mensaje &pMensaje){
return send(this->host->getSocket(), &pMensaje , sizeof(pMensaje) ,0);
}


Esta es la función que recibe:
Código (cpp) [Seleccionar]

Mensaje Receiver::RecvMensaje(){
Mensaje rm;
recv(host->getSocket(), &rm, sizeof(rm), 0);
return rm;
}


El problema esta en el string, ya que es un puntero, puedo enviar el tamaño exacto del paquete del lado del cliente, pero cuando tengo que recibirlo no se de que tamaño es el paquete, si alguien me puede ayudar!!!
<<<--Basura-->>>

ThePinkPanther

#1
Cita de: <<<-Underwar->>> en 28 Junio 2013, 06:36 AM
Tengo un problema con los socket cuando envió y recibo, esto es porque tengo punteros en la clase que estoy enviando, entonces al recibirla me da error de:  Segmentation fault;

esta es la situación que tengo:

Clase a enviar:
Código (cpp) [Seleccionar]

#define TAMANO_MENSAJE 50

class Mensaje {
private:
//char mensaje[TAMANO_MENSAJE];
string mensaje;
public:
Mensaje();
Mensaje(char);
string getMensaje(){return mensaje;}
};



Esta es la función que envía:
Código (cpp) [Seleccionar]

int Sender::SendMensaje(Mensaje &pMensaje){
return send(this->host->getSocket(), &pMensaje , sizeof(pMensaje) ,0);
}


Esta es la función que recibe:
Código (cpp) [Seleccionar]

Mensaje Receiver::RecvMensaje(){
Mensaje rm;
recv(host->getSocket(), &rm, sizeof(rm), 0);
return rm;
}


El problema esta en el string, ya que es un puntero, puedo enviar el tamaño exacto del paquete del lado del cliente, pero cuando tengo que recibirlo no se de que tamaño es el paquete, si alguien me puede ayudar!!!

y el tamaño del paquete que recibes es el mismo de la clase supongo ,si recibes paquetes incompletos capaz que te puede ayudar el MSG_WAITALL que es una señalizacion de recv q  se utiliza para que no devuelva el mensaje hasta que el buffer suministrado este completo..

recv(host->getSocket(), &rm, sizeof(rm), MSG_WAITALL);

si no es esto, no entendi bien .

pero ...

no estas enviando la cantidad de bytes que ocupa un objeto de la clase mensaje??? , y no estas recibiendo la cantidad de bytes que ocupa un objeto de esa misma clase?? suponiendo que las clases son iguales para los 2 programas

eferion

#2
Código (cpp) [Seleccionar]

std::string prueba;

std::cout << sizeof( prueba ) << std::endl;

prueba = "ASDFASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDASDFASDFASDFA";

std::cout << sizeof( prueba ) << std::endl;


resultado:
32
32

expilcación:

sizeof es un operador estático que se resuelve en tiempo de compilación, por este motivo no te va a devolver nunca el tamaño real de un buffer dinámico.

Para trabajar con sockets suele ser más adecuado crear estructuras con tamaños definidos y delimitados y enviar esos paquetes se usen o no todos los bytes.

Me explico:
Código (cpp) [Seleccionar]

struct Paquete
{
 char[50] cadena;
};

// ...

int Sender::SendMensaje(Mensaje &pMensaje)
{
 struct Paquete to_send;
 strncpy( to_send.cadena, pMensaje.getMensaje( ), 49 );

 return send(this->host->getSocket(), &to_send , sizeof(struct Paquete), 0);
}


Y para recibirlo es similar... creas otro paquete, almacenas los datos en el paquete y después guardas el contenido en pMensaje.

0xDani

Ni send() ni recv() trabajan con la clase string directamente, para hacer eso sustituye esto:

Código (cpp) [Seleccionar]
return send(this->host->getSocket(), &pMensaje , sizeof(pMensaje) ,0);

Que no tiene mucho sentido, por esto:

Código (cpp) [Seleccionar]
return send(this->host->getSocket(), pMensaje.getMensaje().c_str() , pMensaje.getMensaje().size() ,0);

Y lo mismo con la función que recibe.

Saludos.
I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM

<<<-Basura->>>

Cita de: 0xDani en 29 Junio 2013, 20:33 PM

Código (cpp) [Seleccionar]
return send(this->host->getSocket(), pMensaje.getMensaje().c_str() , pMensaje.getMensaje().size() ,0);


El problema es que, cuando recibe no se sabe cuantos bytes vienen, y también que string es un puntero, entonces causa Segmentation fault, Creo que lo mejor es trabajar con datos estáticos, para evitar problemas, pero lo que quería era optimizar el trafico de red. pero creo que es un poco difícil
<<<--Basura-->>>

eferion

El tráfico de red se puede optimizar... pero mi consejo es ir por partes... primero haz que funcione y luego lo optimizas.


<<<-Basura->>>

Cita de: eferion en  2 Julio 2013, 10:01 AM
El tráfico de red se puede optimizar... pero mi consejo es ir por partes... primero haz que funcione y luego lo optimizas.

Si te digo que ya funciona que lo que busco es optimizar??
<<<--Basura-->>>

eferion

jajajajaja.

Por curiosidad, cuántos bytes ocupan los datos que envías ??

si son una docena o incluso unas pocas centenas de bytes olvídate de optimizar, ya que el rendimiento va a ser prácticamente el mismo y a cambio te vas a complicar bastante el envío.

Me explico:

Las redes, sean del tipo que sean, tienen definido un tamaño máximo del paquete de datos que puede circular por ella (MTU).

Si tu envías un paquete de menor tamaño este circula sin problemas... si intentas enviar uno más grande, el equipo tiene que trocearlo en paquetes más pequeños que se envían de forma individual.

El problema cuando se trocean los paquetes depende del protocolo utilizado ( TCP o UDP ):

* TCP es un protocolo negociado, no se pierden paquetes y todos llegan ordenados, pero es lento por toda la negociación que lleva asociada... en este caso trocear paquetes implica un período de latencia mayor y para determinadas aplicaciones esto es un problema.

* UDP es un protocolo más crudo, la negociación la tienes que programar tú, los paquetes pueden perderse e incluso llegar desordenados. Debido a la falta de negociación, el protocolo es bastante más rápido. El problema asociado a este protocolo viene de que no posees control sobre los paquetes troceados... pueden producirse problemas si se pierde algún paquete...

Para que te hagas una idea, valores normales de MTU son 576 y 1500 bytes. En redes locales el valor normal es 1500.

Enviar un paquete de 1500 bytes a través de una red local típica ( 100 Mbps ) llevaría ( 1500 * 8 ) /  1e8 = 0,00012 s = 0,12 ms ( milisegundos ).

Si en vez de enviar 1500 bytes consigues reducirlo a 1000 el paquete se enviará en 0,08 ms.

En serio te compensa complicarte la programación del envío y la recepción de los paquetes para ahorrarte 40 microsegundos por paquete??

Aún así, en el caso de que tuvieses que enviar paquetes grandes ( imagínate que necesitas enviar un archivo ), la opción más empleada es dividir el archivo en paquetes de un tamaño preestablecido ( por ejemplo 400 bytes ) y enviar cada uno de esos paquetes tal cual. Luego en el receptor se reensambla el fichero y listo.

Nota: Y antes de que alguno me salte a la yugular, la conversión de Kb a b depende del medio... en memorias y discos hay que dividir por 1024, en redes el factor es 1000.


<<<-Basura->>>

Toda esa teoría que me explicaste ya la conocía de antemano, los bytes que envió son variados, ya que son diferentes clases y diferentes tamaños.
El problema que tenia era cuando enviaba punteros... se enviaban perfectamente, pero cuando llegaban al otro lado causaban un Segmentation fault?? Entiendes ??
<<<--Basura-->>>

Eternal Idol

Cita de: <<<-Underwar->>> en  2 Septiembre 2013, 04:58 AM
Toda esa teoría que me explicaste ya la conocía de antemano, los bytes que envió son variados, ya que son diferentes clases y diferentes tamaños.
El problema que tenia era cuando enviaba punteros... se enviaban perfectamente, pero cuando llegaban al otro lado causaban un Segmentation fault?? Entiendes ??

Muy sencillo no podes enviar punteros ... hace una copia de los datos y envialos. En otra maquina (incluso en otro proceso) el espacio de memoria es totalmente independiente asi que el puntero es invalido o peor, apunta a otra cosa ...
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón