Nous écrivons un projet où un client génère des requêtes XML, les envoie à un serveur, qui analyse la requête et renvoie les informations demandées dans une chaîne XML.Envoi d'un message xml en pièces via un socket TCP en utilisant Qt
L'application fonctionne correctement lorsque les réponses xml sont petites, mais lorsqu'elles dépassent environ 2500 caractères, elles sont parfois tronquées du côté client. Je dis parfois parce que lorsque le client et le serveur s'exécutent sur la même machine et communiquent via l'adresse de la maison 127.0.0.1, les réponses sont très bien analysées. Cependant, lorsque le client et le serveur se trouvent sur des machines différentes et communiquent sur un réseau local, le client coupe le message à environ 2500 caractères.
La communication est effectuée par des sockets tcp. Nous utilisons Qt, le client a un qTCPsocket, et le serveur un qTCPserver et un pointeur vers un qtcpsocket.
Nous pensons qu'une solution possible à notre problème consiste à envoyer le fichier XML en morceaux, soit séparés par nombre de caractères ou par étiquette. Bien qu'il soit facile pour nous de diviser le message en plusieurs parties, envoyer les parties et demander au client ou au serveur de lire et de compiler les parties dans une requête XML nous cause des problèmes. Par exemple, nous voulions tester le fait que le client envoie une requête en plusieurs parties.
Voici notre appel de fonction client pour envoyer une requête. xmlReq est généré ailleurs où et passé. Comme exemple de rupture du message en parties, nous supprimons la balise de fermeture de la requête xml, puis nous l'envoyons comme une autre pièce plus tard.
QString ClientConnection::sendRequest(QString xmlReq)
{
this->xmlRequest = xmlReq;
QHostAddress addr(address);
QList<QString> messagePieces;
xmlRequest.remove("</message>");
messagePieces.append(xmlRequest);
messagePieces.append("</message>");
client.connectToHost(addr,6789);
if(client.waitForConnected(30000))
{
for(int i = 0; i < messagePieces.length();i++)
{
client.write(messagePieces[i].toAscii(),messagePieces[i].length()+1);
qDebug() << "Wrote: " << messagePieces[i];
}
}
char message[30000] = {0};
xmlReply = "";
if(client.waitForReadyRead(30000)){
client.read(message,client.bytesAvailable());
}else{
xmlReply = "Server Timeout";
}
client.close();
xmlReply = (QString) message;
return xmlReply;
}
Suivant est notre code serveur. Il est écrit de telle façon qu'il est supposé lire les messages du client jusqu'à ce qu'il voit la balise de fermeture de xml, puis traiter les données et renvoyer la réponse au client.
Ceci est le code qui démarre le serveur.
//Start the server, pass it the handler so it can perform queries
connect(&server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
server.listen(QHostAddress::Any, 6789);
Quand il obtient une nouvelle connexion, il appelle la fente de acceptConnection qui ressemble à ce
void CETServer::acceptConnection()
{
client = server.nextPendingConnection();
connect(client, SIGNAL(readyRead()), this, SLOT(startRead()));
}
Le startRead ressemble à ceci:
void CETServer::startRead()
{
char buffer[1024*30] = {0};
client->read(buffer, client->bytesAvailable());
QString readIn;
readIn = (QString) buffer;
ui->statusText->appendPlainText("Received: " + readIn);
//New messages in will be opened with the xml version tag
//if we receive said tag we need to clear our query
if (readIn.contains("<?xml version =\"1.0\"?>",Qt::CaseSensitive))
{
xmlQuery = "";
}
//add the line received to the query string
xmlQuery += readIn;
//if we have the clsoe message tag in our query it is tiem to do stuf with the query
if(xmlQuery.contains("</message>"))
{
//do stuff with query
ui->statusText->appendPlainText("Query received:" + xmlQuery);
QString reply = this->sqLite->queryDatabase(xmlQuery);
xmlQuery = "";
this->commandStatus(reply);
if(client->isWritable()){
//write to client
client->write(reply.toAscii(),reply.length()+1);
ui->statusText->appendPlainText("Sent to client: " + reply);
client->close();
}
}}
Dans mon esprit, la lecture de départ est codé de telle sorte qu'à chaque fois que le client écrit un message, le serveur le lit et l'attache à la xmlRequest que le serveur stocke. Si le message contient la balise de fermeture xml, il traite la requête. Ce qui se passe cependant, c'est que si le client effectue des écritures successives, le serveur ne les lit pas tous, seulement le premier, et ne reçoit jamais la balise de fermeture xml, et ne traite donc aucune requête.
La question à laquelle je dois répondre est la suivante: pourquoi le serveur ne répond pas aux écritures multiples des clients? Comment dois-je faire pour que je puisse envoyer une chaîne de caractères en morceaux, et que le serveur lise toutes les pièces et les transforme en une seule chaîne?
Ceci est un trou de sécurité: "char buffer [1024 * 30] = {0}; client-> read (buffer, client-> bytesAvailable());" Il peut y avoir plus d'octets disponibles que l'ajustement dans votre tampon, puis vous avez un dépassement de tampon. –