qt network explained (portuguese)

23
1 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer] ECOSYSTEM

Upload: microsoft-mobile-developer

Post on 19-May-2015

464 views

Category:

Technology


4 download

DESCRIPTION

Desenvolver uma aplicação que precisa de comunicar com a rede não precisa ser complicado. Neste webinar será mostrado como o Qt torna programação para rede muito mais simples. Será dado um rápido overview de como criar sockets UDP e TCP, broadcast e multicast além de fazer requisições REST usando somente a API do QtNetwork.

TRANSCRIPT

Page 1: Qt Network Explained (Portuguese)

1 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

ECOSYSTEM

Page 2: Qt Network Explained (Portuguese)

QtNetwork explained

2 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

Page 3: Qt Network Explained (Portuguese)

TÓPICOS

3 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

• Introdução ao QtNetwork

• Por que usar QtNetwork

• Sockets● QAbstractSocket● QTcpSocket

– QsslSocket● QTcpServer● QudpSocket

– Broadcast– Multicast (somente 4.8 !symbian)

Page 4: Qt Network Explained (Portuguese)

TÓPICOS

4 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

• High level networking● QnetworkAccessManager● QnetworkConfiguration● QnetworkConfigurationManager● QnetworkSession● QnetworkRequest● QNetworkReply

Page 5: Qt Network Explained (Portuguese)

Introdução ao QtNetwork• QtNetwork é um módulo do Qt

• Provê uma interface cross platforma para escrever aplicações

cliente servidor TCP/IP

• Suporta proxy

• Possui classes para realizar requests http e ftp, acessar web

services e tratar suas respostas.

• Pegar informações sobre dispositivos de rede

• É possível ainda gerenciar o estado de conexão com a rede, ter

configurações específicas para cada uma e realizar ações.

Page 6: Qt Network Explained (Portuguese)

Por que usar QtNetwork?int main(){ int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == 1) { printf("can not create socket"); exit(1); } struct sockaddr_in saddr; bzero(&saddr, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(1100); saddr.sin_addr.s_addr = htonl(INADDR_ANY);

if (bind(fd,(struct sockaddr *)&saddr, sizeof(saddr)) == 1) { printf("error bind failed"); exit(1); }

if (listen(fd, 10) == 1) { printf("error listen failed"); exit(1); } for(;;) { int connfd = accept(fd, NULL, NULL); if(connfd <= 0) { printf("error accept failed"); exit(1); }

write(connfd, "Hello world!\n", 13); close(connfd); }

return 0;}

int main(){ QCoreApplication app(argc, argv);

QTcpServer server; server.listen(QHostAddress::Any, 1100);

while (server.waitForNewConnection()) { do { QTcpSocket *socket = server.nextPendingConnection(); socket->write(“Hello, world!”); socket->disconnectFromHost(); socket->waitForDisconnected(); delete socket; } while (server.hasPendingConnections()); }}

Page 7: Qt Network Explained (Portuguese)

Sockets: QAbstractSocket

7 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

• QabstractSocket é uma camada de abstração multi plataforma para api nativa de network

• Implementa TCP, UDP e sockets locais• Herda de QIODevice

Page 8: Qt Network Explained (Portuguese)

Sockets: QTcpSocket● Subclasse de conveniência do QAbstractSocket

● Pode ser utilizado pra implementar vários tipos protocolos

● Stream de dados contínuo

● Poder ser usado de maneira asíncrona ou síncrona.

Page 9: Qt Network Explained (Portuguese)

Sockets: QTcpSocketServerSocket::ServerSocket(QObject *parent) : QTcpSocket(parent){ connect(this, SIGNAL(readyRead()), this, SLOT(onReadyRead()));}

void ServerSocket::onServerInfoResponse(const QVariantMap &map){ QJson::Serializer serializer;

write(serializer.serialize(map));

flush();}

void ServerSocket::onServerStatusChanged(const QString &status) { QVariantMap map; map["what"] = "server"; map["action"] = "statusChanged"; map["status"] = status;

QJson::Serializer serializer; write(serializer.serialize(map)); flush();}

void ServerSocket::onReadyRead(){ while (canReadLine()) { QByteArray line = readLine();

bool parserOk = true; QJson::Parser parser; QVariant var = parser.parse(line, &parserOk);

if (!parserOk) { qWarning() << Q_FUNC_INFO << "json error at" << parser.errorLine() << parser.errorString(); } else { QVariantMap map = var.toMap(); QString what = map["what"].toString(); if (what == "server") { QString action = map["action"].toString(); if (action == "info") { emit serverInfoRequested(); } } } }}

ClientSocket::ClientSocket(QObject *parent) : QTcpSocket(parent){ connect(this, SIGNAL(readyRead()), this, SLOT(onReadyRead()));

connect(this, SIGNAL(disconnected()), this, SLOT(onDisconnected()));

connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));}

void ClientSocket::onDisconnected(){ qDebug() << "[ClientSocket] Client disconnected!";}

void ClientSocket::onError(QAbstractSocket::SocketError error){ qDebug() << "[ClientSocket] Error: " << error;}

void ClientSocket::requestServerInfo(){ QVariantMap map; QJson::Serializer serializer;

map["what"] = "server"; map["action"] = "serverInfo";

write(serializer.serialize(map)");}void ClientSocket::onQJsonParsingFinished(const QVariant &json, bool ok, const QString &error_msg){ if (!ok) { qWarning() << Q_FUNC_INFO << "json error at" << error_msg; return; }

QVariantMap map = json.toMap(); QString what = map["what"].toString(); if (what == "server") { QString action = map["action"].toString(); if (action == "serverInfo") { emit serverInfoReceived(map); } }}

Page 10: Qt Network Explained (Portuguese)

Sockets: QTcpServer● Precisa receber conexões? Essa é a classe certa.

● Pode ser single threaded or multi threaded

● Single threaded● Um ou vários sockets usando mesmo Event loop

● Ou Bloqueante

● Multi threaded● Um socket por thread

– Bloqueante

– Ou um Event loop por thread

Page 11: Qt Network Explained (Portuguese)

Sockets: QTcpServerServer::Server(QObject *parent) : QtcpServer(parent) , m_serverInfo(){}

void Server::start(){ listen(QHostAddress::Any, 12345);}

void Server::incomingConnection(int socketDescriptor) { ServerSocket *sock = new ServerSocket; sock->setSocketDescriptor(socketDescriptor); QThread *thread = new QThread; sock->moveToThread(thread);

connect(sock, SIGNAL(disconnected()), sock, SLOT(deleteLater())); connect(sock, SIGNAL(destroyed()), thread, SLOT(quit())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

connect(this, SIGNAL(statusChanged(const Qstring &)), sock, SLOT(onServerStatusChanged(const Qstring &)));

connect(sock, SIGNAL(serverInfoRequested()), this, SLOT(onServerInfoRequested()));

thread->start();}

void Server::onServerInfoRequested(){ ServerSocket *sock = qobject_cast<ServerSocket*>(sender()); if (!sock) return;

QMetaObject::invokeMethod(sock, "onServerInfoResponse", Q_ARG(QVariantMap, m_serverInfo));}

Page 12: Qt Network Explained (Portuguese)

Sockets: QudpSocket BroadcastBroadcastAnnounce::BroadcastAnnounce(QObject *parent)

: QObject(parent)

, m_socket(new QUdpSocket(this))

, m_timer(new QTimer(this))

, m_serverInfo()

{

connect(m_timer, SIGNAL(timeout()), this, SLOT(sendDatagram()));

}

void BroadcastAnnounce::start()

{

if (m_timer->isActive())

m_timer->stop();

m_timer->start(1000);

}

void BroadcastAnnounce::stop()

{

m_timer->stop();

}

void BroadcastAnnounce::setServerInfo(const QVariantMap &map)

{

m_serverInfo = map;

}

void BroadcastAnnounce::sendDatagram()

{

QByteArray datagram;

QDataStream out(&datagram, QIODevice::WriteOnly);

out.setVersion(QDataStream::Qt_4_7);

out << QVariant(m_serverInfo);

m_socket->writeDatagram(datagram.data(), datagram.size(), QHostAddress::Broadcast, UDP_PORT);

}

Page 13: Qt Network Explained (Portuguese)

Sockets: QudpSocket BroadcastBroadcastAnnounce::BroadcastAnnounce(QObject *parent)

: QObject(parent)

, m_socket(new QUdpSocket(this))

, m_timer(new QTimer(this))

, m_serverInfo()

{

connect(m_timer, SIGNAL(timeout()), this, SLOT(sendDatagram()));

}

void BroadcastAnnounce::start()

{

if (m_timer->isActive())

m_timer->stop();

m_timer->start(1000);

}

void BroadcastAnnounce::stop()

{

m_timer->stop();

}

void BroadcastAnnounce::setServerInfo(const QVariantMap &map)

{

m_serverInfo = map;

}

void BroadcastAnnounce::sendDatagram()

{

QByteArray datagram;

QDataStream out(&datagram, QIODevice::WriteOnly);

out.setVersion(QDataStream::Qt_4_7);

out << QVariant(m_serverInfo);

m_socket->writeDatagram(datagram.data(), datagram.size(), QHostAddress::Broadcast, UDP_PORT);

}

BroadcastDiscover::BroadcastDiscover(QObject *parent) : QObject(parent) , m_socket() , m_timer(new QTimer(this)){ connect(m_timer, SIGNAL(timeout()), this, SLOT(stop()));}

void BroadcastDiscover::start(){ m_socket = new QUdpSocket(this); m_socket->bind(UDP_PORT, QUdpSocket::ShareAddress); connect(m_socket, SIGNAL(readyRead()), this, SLOT(processDatagrams())); m_timer->start(10000);}

void BroadcastDiscover::stop(){ disconnect(m_socket, SIGNAL(readyRead()), this, SLOT(processDatagrams())); m_socket->close(); emit timeout();}

void BroadcastDiscover::processDatagrams(){ QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender()); if (!socket) return;

while (socket->hasPendingDatagrams()) { QByteArray datagram; QHostAddress host;

datagram.resize(socket->pendingDatagramSize()); socket->readDatagram(datagram.data(), datagram.size(), &host);

QVariant message; QDataStream dataStream(&datagram, QIODevice::ReadOnly); dataStream >> message;

const QVariantMap map = message.toMap(); if (map["app_id"].toString() == APP_ID) { const QString action = map["action"].toString(); if (action == "serverAnnounce") { emit serverFound(map); } } }}

Page 14: Qt Network Explained (Portuguese)

Sockets: QudpSocket MulticastMulticastAnnounce::MulticastAnnounce(QObject *parent) : QObject(parent) , m_socket(new QUdpSocket(this)) , m_timer(new QTimer(this)) , m_serverInfo(){ connect(m_timer, SIGNAL(timeout()), this, SLOT(sendDatagram()));

m_socket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1);}

void MulticastAnnounce::start(){ if (m_timer->isActive()) m_timer->stop();

m_timer->start(1000);}

void MulticastAnnounce::stop(){ m_timer->stop();}

void MulticastAnnounce::setServerInfo(const QVariantMap &map){ m_serverInfo = map;}

void MulticastAnnounce::sendDatagram() { QByteArray datagram; QDataStream out(&datagram, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_8); out << QVariant(m_serverInfo);

m_socket->writeDatagram(datagram.data(), datagram.size(), QHostAddress("239.255.43.21"), UDP_PORT);}

MulticastDiscover::MulticastDiscover(QObject *parent) : QObject(parent) , m_socket() , m_timer(new QTimer(this)){ connect(m_timer, SIGNAL(timeout()), this, SLOT(stop()));}

void MulticastDiscover::start(){ m_socket = new QUdpSocket(this); m_socket->bind(UDP_PORT, QUdpSocket::ShareAddress); m_socket->joinMulticastGroup(QHostAddress("239.255.43.21"));

connect(m_socket, SIGNAL(readyRead()), this, SLOT(processDatagrams())); m_timer->start(10000);}

void MulticastDiscover::stop(){ disconnect(m_socket, SIGNAL(readyRead()), this, SLOT(processDatagrams())); m_socket->close(); emit timeout();}

void MulticastDiscover::processDatagrams(){ QUdpSocket *socket = qobject_cast<QUdpSocket *>(sender()); if (!socket) return;

while (socket->hasPendingDatagrams()) { QByteArray datagram; QHostAddress host;

datagram.resize(socket->pendingDatagramSize()); socket->readDatagram(datagram.data(), datagram.size(), &host);

QVariant message; QDataStream dataStream(&datagram, QIODevice::ReadOnly); dataStream >> message;

const QVariantMap map = message.toMap(); if (map["app_id"].toString() == APP_ID) { const QString action = map["action"].toString(); if (action == "serverAnnounce") { emit serverFound(map); } } }}

Page 15: Qt Network Explained (Portuguese)

Sockets: QUdpSocket● Subclasse de conveniência do QabstractSocket para

UDP

● Envio de pacotes de dados ao invés de stream contínuo

● Possui suporte a Broadcast

● Desde o Qt 4.8 suporte a Multicast

Page 16: Qt Network Explained (Portuguese)

QnetworkConfigurationManager

16 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

1- Definir o Ponto de Acesso

QNetworkConfigurationManager manager;

//Define que o usuário pode escolher um ponto de acesso

const bool canStartIAP = (manager.capabilities()& QnetworkConfigurationManager::CanStartAndStopInterfaces);

//Retorna a configuração padrão atual

manager.defaultConfiguration();

Page 17: Qt Network Explained (Portuguese)

QnetworkConfiguration

17 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

1- Definir o Ponto de Acesso

QNetworkConfigurationManager manager;

//Define que o usuário pode escolher um ponto de acesso

const bool canStartIAP = (manager.capabilities()& QNetworkConfigurationManager::CanStartAndStopInterfaces);

//Se existe um ponto de acesso padrao. Basta utiliza-lo usando a configuracao padrao do QNetWorkConfigurarionManager

QNetworkConfiguration cfg = manager.defaultConfiguration();

if (!cfg.isValid() || !canStartIAP) {

// Pontos de acesso nao encontrados ou impossivel se conectar

// Alertar usuario e fazer tratamento de erro

return;

}

Page 18: Qt Network Explained (Portuguese)

QnetworkSession

18 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

// Caso a conexao tenha ocorrido com sucesso, abrir um QNetworkSession usando a configuracao padrao

m_session = new QNetworkSession(cfg);

//Conectar sinais necessarios

connect(m_session, SIGNAL(closed()), this, SLOT(closed()));

connect(m_session, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(stateChanged(QNetworkSession::State)));

connect(m_session, SIGNAL(error(QNetworkSession::SessionError)), this, SLOT(error(QNetworkSession::SessionError)));

Abrir aconexao

m_session->open();

// Espera a sessão ser aberta e continua a partir dai

m_session->waitForOpened();

Para fechar a sessão, usar o slot finished()

Page 19: Qt Network Explained (Portuguese)

QnetworkAccessManager

19 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

1- Criar um Network Access Manager

nam = new QNetworkAccessManager(this);

2- Conectar o sinal finished a um slot para tratar o resultado

QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),

this, SLOT(finishedSlot(QNetworkReply*)));

Page 20: Qt Network Explained (Portuguese)

QnetworkRequest

20 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

1- Criar um Network Access Manager

nam = new QNetworkAccessManager(this);

2- Conectar o sinal finished a um slot para tratar o resultado

QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),

this, SLOT(finishedSlot(QNetworkReply*)));

3- Criar o Request

QUrl url(http://query.yahooapis.com/v1/public/yql);

url.addQueryItem(QUERY_PARAM,

QLatin1String("select+*+from+geo.placefinder+where+text=\"")

+ "Sao Paulo" + QLatin1String("\""));

url.addQueryItem("format", "json");

QnetworkRequest request(url);

Page 21: Qt Network Explained (Portuguese)

QNetworkReply

21 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

1- Criar um Network Access Manager

nam = new QNetworkAccessManager(this);

2- Conectar o sinal finished a um slot para tratar o resultado

QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),

this, SLOT(finishedSlot(QNetworkReply*)));

3- Criar o Request

QUrl url(http://query.yahooapis.com/v1/public/yql);

url.addQueryItem(QUERY_PARAM,

QLatin1String("select+*+from+geo.placefinder+where+text=\"")

+ "Sao Paulo" + QLatin1String("\""));

url.addQueryItem("format", "json");

QnetworkRequest request(url);

4- Guardar o reply do request par ser usado como identificador da resposta

QNetworkReply* reply = nam->get(request)

Page 22: Qt Network Explained (Portuguese)

QNetworkReply

22 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

4- Tratar o Reply

void MyHttpEngine::finishedSlot(QNetworkReply* reply) {

// Ler Atributos do Repply como ocodigo de Status HTTP

QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

void MyHttpEngine::finishedSlot(QNetworkReply* reply) {

// Ler Atributos do Repply como o codigo de Status HTTP

QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

// Ou a URL, se esta tiver sido redirecionada:

QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);

// Verificar se houve erro

if (reply->error() == QnetworkReply::NoError) {

// Se nao houve erro, ler os dados da resposta

//Ex1: Criando um QImage da resposta

QImageReader imageReader(reply);

QImage pic = imageReader.read();

}

}

Page 23: Qt Network Explained (Portuguese)

Canais de comunicação

23 INdT 2012 | Filename.pptx v. 0.1 YYYY-MM-DD Author Document ID [Edit via Insert > Header & Footer]

• @nokiadev_brasil• [email protected]