2010-11-25 25 views
6

Tengo un problema con las bibliotecas boost asio. Intenté con éxito crear un socket entre un cliente y un servidor, esto implica la creación de resolvedores para especificar la IP y el puerto para el servidor (el servidor solo requiere el puerto) y otros objetos, pero, lo más importante, es necesario usar write y read_some como funciones para leer y escribir desde/en el socket. Realmente agradecería usar una secuencia, y esto es posible en Asio de refuerzo, pero eso es extraño ... En casi todos los ejemplos que usan flujos, para crear un servidor es necesario proporcionar un puerto, vale, hablemos del cliente ... lado del cliente, es necesario utilizar el constructor iostream para especificar las coordenadas para la conexión de la corriente, aquí está el código:Crear un iostream usando boost asio especificando ip y puerto

tcp::iostream() s(argv[1], "daytime"); 

Bueno, yo no entiendo muy bien lo que se aprobó en el primer parámetro y realmente no sé qué día podría representar alguna vez ... Básicamente, aquí estoy diciendo: "Oye la transmisión, debe conectarse a este servidor ...", pero ¿cómo puedo especificar la IP y el puerto de ese servidor? Tenga en cuenta que, por el contrario, todo lo que es del lado del servidor casi transparente:

boost::asio::io_service io_s; 
tcp::acceptor acc(io_s, tcp::endpoint(tcp::v4(), 1950)); 
for (;;) { 
    tcp::iostream stream; 
    acc.accept(*stream.rdbuf()); 
    stream << "Message" << std::endl; 
} 

Usando este modelo, me gustaría utilizar

stream << mymessage_to_send << std::endl; 
stream >> a_string_containing_my_message; 

con el fin de enviar y recibir. ¿Cómo puedo hacer esto? Muchas gracias.

Respuesta

1

He escrito un sistema cliente/servidor usando Boost.Asio. La fuente está disponible en GitHub: Client.cpp y Server.cpp. Usar Boost.Serialization junto con Boost.Asio me permite enviar estructuras de datos arbitrarias a través del cable. Debo decir que es bastante impresionante!

+0

bien, va a comprobar de inmediato ... Gracias – Andry

+0

Eres libre de hacerme preguntas sobre mi implementación, si lo desea. ¡Buena suerte! –

+0

Bueno, estoy intentando algunas cosas mirando tu código ... No tengo tanta experiencia como tú ... bueno, las preguntas van a llegar, ahora puedo decir: Código increíble !!!!! – Andry

17

El código de ejemplo asio impulso que citó:

tcp::iostream s(argv[1], "daytime"); 

utiliza "día" como una búsqueda en la tabla de servicios (normalmente en/etc/services en un sistema Linux), que identificaría que el puerto de el servicio durante el día es 13.

Si desea conectarse a un puerto que no es uno de los servicios conocidos, puede hacerlo con algo como:

tcp::iostream s("localhost", "57002"); 

Nota º en el número de puerto se proporciona como una cadena, no como un entero corto sin signo, como uno podría estar tentado de probar.

Por supuesto, "localhost" se puede sustituir por una dirección IP "127.0.0.1"

+6

Esta debería ser la respuesta seleccionada. – Collin

+1

Aparte del hecho de que no debería haber() después de iostream, de lo contrario, ¿está devolviendo una función? – CashCow

+0

@CashCow - ¡lol! Acabo de copiar desde el OP y aclaré. ¡Pero buen truco! – Arunas

0

Resolvamos los 3 temas aquí:

Creación de la iostream alrededor del lado del cliente toma.

Esto es muy simple:

boost::asio::ip::tcp::iostream socketStream; 
socketStream.connect(hostname, std::to_string(port)); 

usted tiene que comprobar el estado de la corriente para ver si se ha conectado correctamente.

Creación del iostream en el lado del servidor de socket.

Asumiendo que tiene su objeto de aceptor y se ve obligada y escuchar ..

boost::asio::ip::tcp::iostream connectionSocketStream; // from the connection object 
acceptor.accept(*connectionSocketStream.rdbuf()); 

// o

acceptor.async_accept(*connectionSocketStream.rdbuf(), callback); 

donde devolución de llamada es una función que toma un código de error.

Streaming los objetos

Ahora, para el mismo y que aquí en streaming su problema es que al transmitir por la cadena "mensaje" del lado del cliente necesitará saber donde este mensaje comienza y termina, y la regularidad iostream no escribirá nada para especificar esto. Esto es un defecto en iostream en realidad.

Por lo tanto, la respuesta es usar un archivo de impulso, y puede usar un archivo de texto o archivo binario siempre que use los mismos dos extremos. Incluso no importa si un lado está usando big-endian de 64 bits y el otro endian de 32 bits o cualquier otra mezcla.

Usando archivo binario que le envíe un mensaje de esta manera:

boost::archive::binary_oarchive oarch(socketStream, boost::archive::no_header); 
oarch << "Message"; 

Recordar para eliminar la corriente (socketStream, no oarch) cuando haya completado el envío de todo lo que desea enviar en este momento.

y recibir un mensaje

boost::archive::binary_iarchive iarch(socketStream, boost::archive::no_header); 
iarch >> message; 

Se podría potencialmente crear un archivo y utilizarlo en todas partes, especialmente para los de salida. Para el ingreso puede tener problemas si obtiene un error de transmisión, ya que romperá su archivo.

Puede usar un archivo de texto en lugar de uno binario.

El archivo de impulso colocará automáticamente la información del encabezado para que sepa cuándo se completa un objeto y solo le devolverá una vez que tenga un objeto completo o algo roto.

Nota: los tipos primitivos, p. Ej. Std :: string e incluso el vector < int> etc., son manejados automáticamente por un archivo. Sus propias clases necesitarán sobrecargas especiales sobre cómo transmitirlas. Deberías leer la documentación de boost :: archive.

Nota: Puede conectar el objeto de archivo a la secuencia antes de que se haya abierto la secuencia. El archivo funciona alrededor del objeto streambuf que no cambia dependiendo de la apertura de la secuencia con éxito.

Creación sin no_header sería un problema, ya que las tratan archivos inmediatamente a utilizar la corriente en la construcción (para leer o escribir su cabecera)

Cuestiones relacionadas