Qt proporciona un conjunto de API de comunicaciones a través del módulo Qt Network. Este ofrece, tanto clases de bajo nivel para comunicación mediante protocolos de transporte ---como TCP y UDP--- como clases de alto nivel que implementan operaciones usando los protocolos de nivel de aplicación más comunes ---como HTTP o FTP---. Qt incorpora este módulo por dos motivos fundamentales:
Aunque la mayor parte de los sistemas operativos modernos proporcionan una API de acceso a red basado en BSD sockets, algunos introducen funcionalidades adicionales para adaptarlo al modelo de programación preferente en el sistema en cuestión. Este, por ejemplo, es el caso de Windows y la librería Winsock que incorpora. Por tanto, Qt, gracias a su módulo Qt Network, nos proporciona una forma portable de acceder a los servicios de red de los sistemas operativos soportados sin tener que preocuparnos por las particularidades de cada uno.
Las operaciones de red suelen requerir mucho tiempo antes de completarse, por lo que usarlas en un slot del hilo principal implica el bloqueo del bucle de mensajes de la aplicación. Por fortuna, la API BSD sockets permite tanto el uso síncrono como asíncrono de la interfaz. Esta última forma de utilizarla evita el bloqueo del bucle de mensajes al impedir que las llamadas a la interfaz se bloqueen hasta que las operaciones de red son completadas. Sin embargo, implican una forma de programar mucho más compleja para el desarrollador.
La API de bajo nivel de Qt Network es asíncrono por diseño, ocultando toda esa complejidad detrás del bucle de mensajes y del mecanismo de señales y slots común a todo el framework Qt. Aunque la API de bajo nivel ofrece métodos para comunicación síncrona —los métodos waitFor*
, por ejemplo— en cuyo caso no necesitamos bucle de mensajes, su uso no está recomendado si no es en un hilo diferente al hilo principal. Además, las clases del API de alto nivel no ofrecen métodos síncronos, por lo que si se usan es obligatorio disponer de un bucle de mensajes. Debemos tener en cuenta que las API del módulo Qt Network se pueden usar desde hilos diferentes al hilo principal, ya que cada hilo gestionado por la clase QThread tiene su propio bucle de mensajes, que se inicia automáticamente en el método QThread::run()
por defecto.
Funcionalidad
El módulo Qt Network ofrece las siguientes interfaces:
Clases QNetwork*
QNetworkRequest
, QNetworkReply
y QNetworkAccessManager
son una colección de clases que proporcionan una abstracción de alto nivel sobre operaciones y protocolos de comunicación comunes, por ejemplo HTTP y FTP. Cada instancia de la clase QNetworkRequest
representa una petición u operación contra un servicio en red, mientras que las instancias de la clase QNetworkReply
representan la respuesta a esas peticiones. La coordinación de toda esta actividad es responsabilidad de QNetworkAccessManager
, que se encarga de entregar a la red las peticiones una vez han sido creadas y de emitir señales con la respuesta a las mismas cuando son recibidas. También coordina el uso de cookies, peticiones de autenticación y el uso de servidores proxy.
QTcpSocket y QTcpServer
TCP es el protocolo de comunicación utilizado por diversos protocolos de Internet, como HTTP o FTP. QTcpSocket
proporciona acceso de bajo nivel a dicho protocolo. Permite establecer una conexión con una dirección IP y puerto determinado, así como enviar y recibir datos. Estas operaciones son asíncronas, por lo que no bloquean la ejecución del hilo, siendo la clase la que notifica mediante señales tanto las condiciones de error como de cuándo se dispone de nuevos datos para leer. Si lo que se desea es crear una aplicación que reciba conexiones TCP entrantes (como un servidor), lo conveniente es utilizar la clase QTcpServer
. Esta nos permite escuchar en una dirección IP y puerto concreto y aceptar las conexiones entrantes por parte de los clientes. Cada vez que se acepta el intento de conexión de un cliente, se obtiene una instancia de la clase QTcpSocket
con la que podemos comunicarnos con él.
QUdpSocket
UDP es un protocolo de comunicación que también es utilizado por diversos protocolos de Internet. QUdpSocket
proporciona acceso de bajo nivel a dicho protocolo. Permite enviar y recibir paquetes de datos a una dirección IP y puerto concretos, ya que a diferencia de TCP, UDP no provee un flujo continuo de datos, sino que opera mediante el envío de paquetes. Tampoco se provee una clase específica para escuchar por conexiones entrantes —al estilo de QTcpServer
— porque UDP no es un protocolo orientado a conexión. La interfaz de QUdpSocket
simplemente permite preparar el socket para aceptar la recepción de paquetes.
QLocalSocket y QLocalServer
Proporcionan una abstracción similar a la de QTcpSocket
y QTcpServer
, pero para sockets locales. En Windows se implementa haciendo uso de tuberías con nombre, mientras que en UNIX, Linux y otros sistemas POSIX se utilizan sockets de dominio UNIX.
QHostInfo
Se utiliza para obtener la dirección IP asignada a un nombre de máquina concreto a través del servicio DNS (Domain Name Service). Tanto la clase QTcpSocket
como QUdpSocket
hacen esto automáticamente cuando se indica un nombre de máquina y no una dirección IP. Sin embargo, la clase QHostInfo
nos permite hacerlo manualmente, si por cualquier motivo fuera necesario.
QNetworkProxy
Cada instancia de QNetworkProxy
se usa para describir y configurar la conexión a un servidor proxy, que pueden dirigir o filtrar el tráfico entre ambos extremos de una conexión. Un servidor proxy puede ser activado para un socket concreto, a través del método QAbstractSocket::setProxy()
, antes de conectarlo, o en el ámbito de toda la aplicación, a través de la función QNetworkProxy::setApplicationProxy()
.
QNetworkConfigurationManager y QNetworkConfiguration
Estas clases constituyen la interfaz del gestor de portabilidad, que controla el estado de conectividad del dispositivo, permitiendo iniciar y detener las interfaces de red, así como migrar transparentemente entre puntos de acceso. La clase QNetworkConfigurationManager
gestiona la lista de configuraciones de red conocidas por el dispositivo. Una configuración de red describe el conjunto de parámetros usados al iniciar la interfaz de red y es representada por instancias de la clase QNetworkConfiguration
.
Utilizar Qt Network
Para incorporar el módulo en nuestra aplicación, solo tenemos que incluir la declaración de sus clases, añadiendo la siguiente directiva en aquellos archivos donde las vayamos a utilizar:
#include <QtNetwork>
Mientras que para enlazar el módulo con el ejecutable de la aplicación, solo hay que añadir la siguiente línea al archivo .pro
del proyecto:
QT += network
Hecho esto, la mejor forma de aprender a utilizar los recursos del módulo Qt Network es siguiendo los ejemplos disponibles en su documentación:
Ejemplos de QTcpSocket y QTcpServer:
Fortune Client y Fortune Server muestran como desarrollar una aplicación cliente-servidor sobre TCP.
Blocking Fortune Client muestra como usar la interfaz síncrona de QTcpSocket.
Threaded Fortune Server muestra como desarrollar un servidor multihilo donde cada hilo sirve a un cliente.
Ejemplos de QUdpSocket:
Broadcast Sender y Broadcast Receiver muestran como desarrollar un emisor y un receptor sobre UDP.
Multicast Sender y Multicast Receiver muestran como desarrollar aplicaciones que hagan uso de la multidifusión (o multicast).