您的位置:首页 > 编程语言 > Qt开发

用QTJSON、curl与QTSQL、tufao来实现客户端与服务端间通信

2017-07-15 19:43 585 查看

1.开发平台:linux系统上的qt与vim

2.需求:现要实现客户端与服务端之间的通信;服务端采用tufao开源库来作为服务器,同时在服务器上建立一个数据库(采用关系型数据库mysql),用来存储客户端的数据;客户端采用libcurl开源库来发送用户的数据到服务器中,而中间数据包采用json来进行打包,前面的几篇博客已说明json的作用,因此这里不再叙述json的作用;QT很完美的支持了mysql类和json类,因此用qsql来实现数据库的连接和操作,用qjson来打包数据;

3.基本通信模型图如下:



4. qt建立一个项目名为Car,该工程下的所有类或文件如下:



(1)其中Server类继承自QObject类,各文件的源代码为:

Car.pro

*************************************
Car.pro
*************************************
SOURCES += \
main.cpp \
server.cpp

HEADERS += \
server.h

QT += sql network

CONFIG += C++11

LIBS += -ltufao1


main.cpp

*************************************
main.cpp
*************************************
#include<QCoreApplication>
#include"server.h"

int main(int argc,char **argv)
{
QCoreApplication app(argc,argv);
new Server;

return app.exec();
}


server.h

*************************************
server.h
*************************************

#ifndef SERVER_H
#define SERVER_H

#include <QObject>
#include<QString>

#include<QJsonArray>
#include<QJsonObject>
#include<QJsonValue>
#include<QJsonDocument>

#include<tufao-1/Tufao/HttpServer>
#include<tufao-1/Tufao/HttpServerRequest>
#include<tufao-1/Tufao/HttpServerResponse>

#include<QtSql/QSqlDatabase>
#include<QtSql/QSqlError>
#include<QtSql/QSqlQuery>
#include<QtSql/QSqlQuery>

using namespace Tufao;

class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);

QSqlDatabase db;
HttpServer server;

QString  md5(QString str);

QJsonObject login(const QJsonObject& req);
QJsonObject reg(const QJsonObject& req);

void onPostReady(HttpServerRequest& request,
HttpServerResponse& response);

signals:

public slots:
void onRequestReady(Tufao::HttpServerRequest& request,
Tufao::HttpServerResponse& response);

};

#endif // SERVER_H


server.c

*************************************
server.cpp
*************************************

#include "server.h"
#include<QByteArray>
#include<QCryptographicHash>

Server::Server(QObject *parent) : QObject(parent)
{
/* 创建并打开一个或多个数据库连接
* addDatabase()的"QMYSQL"参数指定用于连接的数据库驱动程序的类型
*/
db = QSqlDatabase::addDatabase("QMYSQL");
/* 创建连接对象,打开它以供使用 */

/* 初始化一些连接信息 */
db.setHostName("127.0.0.1");   /* 初始化主机名信息 */
db.setDatabaseName("Car");  /* 初始化数据库名称信息 */
db.setUserName("root");   /* 初始化用户名信息 */

/* 注意下面密码那里填入你自己的数据库的密码 */
db.setPassword("密码");   /* 初始化密码信息 */

/*在初始化这些连接之后,为每个连接建立实时连接,打开(),
* 如果open()失败,则返回false。在这种情况下,调用
* QSqlDatabase :: lastError()来获取错误信息。
*/

if(! db.open())
{
exit(1);
}

server.listen(QHostAddress::Any,8888);

connect(&server,SIGNAL(requestReady(Tufao::HttpServerRequest&,
Tufao::HttpServerResponse&)),
this,SLOT(onRequestReady(Tufao::HttpServerRequest&,
Tufao::HttpServerResponse&)));

}

QString Server::md5(QString str)
{
QByteArray db;
db = QCryptographicHash::hash(str.toUtf8(),QCryptographicHash::Md5 );
return  db.toHex();
}

QJsonObject Server::login(const QJsonObject &req)
{
QJsonObject jsonObj; /* 封装JSON对象 */
QString username = req.value("username").toString();
QString password = req.value("password").toString();

QString md5Password = md5(password); /*  MD5加密 */

QString sql = QString("select * from  People where username = '%1' and password = '%2'")
.arg(username,md5Password);

/* QSqlQuery 执行和操作SQL语句的方法;数据库交互通过使用QSqlQuery类实现,
* 要执行一个SQL语句,只需创建一个QSqlQuery对象并调用如下所示的QSqlQuery :: exec();
*/
QSqlQuery query = db.exec(sql);
/* QSqlQuery构造接受可选QSqlDatabase对象,指定要使用的数据库连接。在上面的代码中
* 没有指定任何连接,因此使用默认连接。如果发生错误,exec()返回false。然后,该错误
* 可用作QSqlQuery :: lastError()
*/

if(query.lastError().type() != QSqlError::NoError)
{
/* 迭代器 QJsonObject :: insert(const QString& key,const QJsonValue& value) */
jsonObj.insert("result",QString("error"));
jsonObj.insert("reason",QString("Add user error"));
}

/* 返回结果的大小(返回的行数) */
if(query.size() != 1)
{
jsonObj.insert("result",QString("error"));
jsonObj.insert("result",QString("username or password error."));
return jsonObj;
}

jsonObj.insert("result",QString("ok"));
return jsonObj;

}

QJsonObject Server::reg(const QJsonObject &req)
{
QJsonObject jsonObj;
QString username = req.value("username").toString();
QString password = req.value("password").toString();

QString md5Password = md5(password);

QString sql = QString("insert into People(username,password) values('%1','%2')")
.arg(username,md5Password);

QSqlQuery query = db.exec(sql);
if(query.lastError().type() != QSqlError::NoError)
{
jsonObj.insert("result",QString("error"));
jsonObj.insert("reason",QString("add user error"));
return jsonObj;
}

jsonObj.insert("result",QString("ok"));
return jsonObj;
}

void Server::onPostReady(HttpServerRequest &request, HttpServerResponse &response)
{
/* recv POST data */
QByteArray byte = request.readBody();

#if 0
data is JSON format packet
{
cmd: login,
username: tom,
password: xxx
}
#endif

/* QJsonDocument类提供一种方法来读取和写入JSON文档;QJsonDocument是一个包装
* 一个完整的JSON文档的类,可以从基于UTF-8编码的基于文本的表示形式以及Qt自己的
* 二进制格式读取和写入该文档
*/
QJsonDocument docu = QJsonDocument::fromJson(byte);

/* QJsonObject类封装JSON对象。JSON对象是键值对的列表,其中键是唯一字符串,值
* 由QJsonValue表示。QJsonObject可以被转换和从QVariantMap。您可以使用size(),
* insert()和remove()项查询(key,value)对的数量,并使用标准C ++迭代器模
* 式对其内容进行迭代。QJsonObject是一个隐式共享的类,并且只要没有被修改就与它创
* 建的文档共享数据。您可以通过QJsonDocument将对象转换为基于文本的JSON 。
*/

/* QJsonObject QJsonDocument :: object()const返回文档中包含的QJsonObject。
* 如果文档包含一个数组,则返回一个空对象。*/
QJsonObject jsonObj = docu.object();
QJsonObject resp;

/* QJsonValue QJsonObject :: value(const QString& key)const
* 返回QJsonValue表示该键的值的关键。*/
QString cmd = jsonObj.value("cmd").toString();
if(cmd == "register")
{
resp = reg(jsonObj);
}
else if(cmd == "login")
{
resp = login(jsonObj);
}
else
{
resp.insert("result",QString("error"));
resp.insert("reason",QString("unknow command"));
}

/* resp ----> QByteArray */
{
QJsonDocument docu(resp);
QByteArray byte = docu.toJson();
response.end(byte);  /* send ---->client */
}

}

void Server::onRequestReady(Tufao::HttpServerRequest &request,
Tufao::HttpServerResponse &response)
{
response.writeHead(HttpResponseStatus::OK);
if(request.method()!= "POST")
{
response.end("not POST error");
return;
}
/* if post, wait data upload */

connect(&request,&HttpServerRequest::end, [&](){
onPostReady(request, response);
});
}

#if 0
void Server::onRequestReady(Tufao::HttpServerRequest& request,
Tufao::HttpServerResponse& response)
{
response.writeHead(HttpResponseStatus::OK);
if(request.method()!= "POST")
{
response.end("not POST error");
return;
}
/* if post, wait data upload */

connect(&request,&HttpServerRequest::end, [&](){
onPostReady(request, response);
});

}

#endif


到这里时,服务端已经完成,为了测试其效果,需要写一个简单的客户端程序来进行验证

5.客户端程序如下:

/*************************************************************************
* File Name: client.c
* Author:    The answer
* Function:  Other
* Mail:      2412799512@qq.com
* Created Time: 2017年07月15日 星期六 19时26分47秒
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <curl/curl.h>
#include "cJSON.h"

int main()
{

cJSON* root = cJSON_CreateObject();

cJSON_AddStringToObject(root, "cmd", "register");
cJSON_AddStringToObject(root, "username", "lxg");
cJSON_AddStringToObject(root, "password", "lxg");

char* p = cJSON_Print(root);
cJSON_Delete(root);

CURL* curl = curl_easy_init();

/* IP地址为服务端的地址,改为自己的ip地址便可 */
curl_easy_setopt(curl, CURLOPT_URL, "http://IP地址:8888");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, p);

curl_easy_perform(curl);
free(p);
curl_easy_cleanup(curl);
return 0;
}


说明:客户端中发送的一个包(json)为:

{

“cmd”: “register”, /* 注意:这里可以是login,或register */

“username”:”xxx”,

“password”:”yyy”

}

6.分别在两个终端中打开并执行服务端和客户端;如下:



客户端的结果为:


这是可以看到服务器中的数据库里面已经有了内容,如下:



一开始数据库是为空的;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: