خانه برنامه نویسی پروژه برنامه نویسی شبکه و ارتباط با سرور در Qt – قسمت دوم
پروژه برنامه نویسی شبکه در محیط برنامه نویسی Qt

پروژه برنامه نویسی شبکه و ارتباط با سرور در Qt – قسمت دوم


۱۴ فروردین ۱۳۹۸
رضا احمدی
802 بازدید
دسته بندی : c++ , Qt creator , برنامه نویسی

در قسمت قبل رابط گرافیکی برنامه را طراحی کردیم و با شرح کلی پروژه و کلاس های کار با شبکه محیط کیوتی و هدف پروژه آشنا شدیم در این قسمت می خواهیم متدهای برنامه نویسی شبکه را پیاده سازی کنیم و برنامه را کامل کنیم.

همانطور که گفتیم پروتکل ارتباطی ما http و برای مثال آدرس سرور ” http://localhost:8080/Qt-mrzx_ir/server.php ” می باشد.

پیاده سازی متدها:

جهت ارسال درخواست به سرور متدهایی متنوعی وجود دارد ولی پرکاربردین متد های موجود دو متد Get , Post می باشد که از لحاظ امنیتی متد post  امنیت نسبتا بالاتری را دارد.

  1. QUrl url(QString("http://localhost:8080/Qt-mrzx_ir/server.php"));
  2.     QNetworkRequest req(url);
  3.     req.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
  4.     QString body="username="+ui->le_uName->text()+"&password="+ui->le_uPass->text();
  5.  
  6.     m_manager->post(req,body.toLatin1());

هنگامی که این درخواست را ارسال کردیم به یک آبجکت از کلاس QNetworkReply نیاز داریم که پاسخ این در خواست را در آن ذخیره کنیم برای این منظور به یک متد(اسلات) نیاز داریم تا وقتی که پاسخ به طور کامل دریافت شد آن متد اجرا و دیتای از جنس QNetworkReply را بخوانیم.

نام این متد را network_reply(QNetworkReply *reply) میگذاریم و سیگنال finished  شی m_manager را به آن وصل میکنیم( در کانستراکتور کلاس اصلی).

connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(network_reply(QNetworkReply*)));

لذا پس از ارسال درخواست متد مورد نظز اجرا دیتایش را از طریق آرگومان کلاس مربوطه ارسال میکن و پس اینکه این دیتا را در یافت کردیم لازم است که آن را روی فرم نمایش دهییم.

  1. void zxMain::network_reply(QNetworkReply *reply)
  2. {
  3.     if(reply->error()==QNetworkReply::NoError)
  4.         QString data=(QString)reply->readAll();
  5.  
  6. }

reply->error() :

اگر خطایی در هنگام دریافت داده رخ دهد آن خطا را از این متد می توانیم بفهمیم.لذا وقتی خطایی وجود نداشت آن دیتای مورد نظز ما است.

پس تا اینجا ما متوجه شدیم که چگونه یک در خواست را بفرستیم و جگونه پاسخ آن دریافت را بدست بیاوریم.

برنامه سرور:

حال نوبت به برنامه سرور رسیده برای سرور یک برنامه ساده php  را درنظر گرفتیم که درصورتیکه نام کاربری و کلمه عبور درست باشد مشخصات بک کاربر را در قالب یک فایل JSON ارسال می کند.

ویکی پدیا: JSON یک استاندارد باز متنی سبک برای انتقال داده‌ها است به گونه‌ای که برای انسان نیز خوانا باشد. جی‌سان از زبان اسکریپت‌نویسی جاوااسکریپت در نشان‌دادن ساختمان داده‌های ساده و آرایه‌های انجمنی مشتق شده‌است. با وجود ارتباط عمیقی که با جاوااسکریپت دارد، جی‌سان مستقل از زبان است و مفسرهایش تقریباً برای هر زبانی موجود هستند.

جی سان یک جایگزین بسیار مناسب بجای زبان xml  می باشد که خوانایی دیتا را آسانتر میکند.

برای مثال یک دیتای json  می تواند مانند زیر باشد:

myObj = {name: "John", age: 31, city: "New York"}

در مثال بالا یک دیتای جی سان با نام myObj داریم که شی name  دارای محتوای john و شی عددی age دارای محتوای عدد 31 و … می باشند.

در زبان برنامه نویسی php توابع متعددی برای کار با دیتای جی سان دارد و توان آرایه های این زبان را به داده های جی سان و داده های  جی سان را به آرایه هایی تبدیل کرد.

برای این منظور سورس سرور ما به شرح زیر است:

  1. <?php
  2. /*
  3.  این یک مثال ساده است برای ارتباط یک نرم افزار در محیط کیوتی با سرور
  4.  در این مثال داده ای از جنس دیتای جی سان به کاربر ارسال خواهد شد
  5.  
  6. https://mrzx.ir
  7. Reza.Ahmadi
  8. */
  9. header('Content-Type: application/json; charset=utf-8');
  10.  
  11. if(isset($_POST["username"]) && isset($_POST["password"]))
  12.     if(($_POST["username"]=="reza") && ($_POST["password"]=="12345") )   
  13.     {                
  14.         $user=array("name"=>"رضا احمدی",
  15.                     "phone"=>"09379206787",
  16.                     "brithday"=>"1372/06/21",
  17.                     "avatar"=>"http://localhost:8080/Qt-mrzx_ir/logo.png",
  18.                     "error"=>"noError");
  19.  
  20.         $mydata=json_encode($user);
  21.         echo $mydata;
  22.     } 
  23.     else
  24.     {
  25.         $user=array("error"=>"UserOrPass");
  26.  
  27.         $mydata=json_encode($user);
  28.         echo $mydata;
  29.     }
  30. ?>

داده های JSON در Qt :

در Qt برای دسترسی به دیتاهای از نوع جی سان  می توانیم از دو کلاس زیر استفاده کنیم:

QJsonDocument

کلاسی است که با استفاده از آن می توانیم داده هایی از نوع json را با فرمت متنی utf-8  بخوانیم و بنویسیم .

QJsonObject

کلاسی است که به ما اجازه دسترسی به اشباء جی سان را می دهد.

پس متد network_reyply() می تواند به شرح زیر باشد :

  1. void zxMain::network_reply(QNetworkReply *reply)
  2. {
  3.     if(reply->error()==QNetworkReply::NoError)
  4.     {
  5.         QString data=(QString)reply->readAll();
  6.         QJsonDocument jsonDoc=QJsonDocument::fromJson(data.toUtf8());
  7.         m_jsonData=jsonDoc.object();
  8.         qDebug()<<data;
  9.         if(m_jsonData["error"].toString()=="noError")
  10.            {
  11.             QString name(m_jsonData["name"].toString()),
  12.                     phone(m_jsonData["phone"].toString()),
  13.                     brithday(m_jsonData["brithday"].toString());
  14.             QUrl avatarUrl=m_jsonData["avatar"].toString();
  15.             send_request(avatarUrl);
  16.         }
  17.         else
  18.             QMessageBox::information(this,"خطا","نام کاربری یا کلمه عبور اشتباه می باشد.");
  19.     }
  20.     else
  21.         QMessageBox::information(this,"خطا",reply->errorString());
  22. }

دقت نمایید که m_jsonData از کلاس  QjsonObjectمی باشد .حال ما دیتاهای خود را دریافت کردیم کافی  است انها مقادیر آن  ها را برای اشیاء درون فرم کیوتی که ایجاد کردیم تنظیم کنیم و به کاربر نمایش دهیم. همانطور که پاسخ سرور مشخص است برای avatar آدرس ان فایل برای ما ارسال شده لذا باید آن فایل را دانلود کرده سپس آن را نمایش دهیم.

دانلود فایل از سرور :

بدین منظور مانند عملیاتی که برای دریافت یک دیتای انجام دادیم اینبار آن دیتا را در یک ابجکت از کلاس QByteArray ذخیره و سپس آن دیتا را با فرمت تصویر (PNG.) ذخیره کنیم و درون یک شی کلاس QPixmap آن را بارگذاری کنیم سپس دفرم مربطه نمایش دهیم.

ابتدا یک شی جدید از کلاس QNetworkAccessManager با نام m_fileDownloader  ایجاد میکنیم و آن را به یک متد جهت پایان دانلود با نام downloaded(QNetworkReply *reply) متصل می کنیم:

connect(m_fileDownloader,SIGNAL(finished(QNetworkReply*)),this,SLOT(downloaded(QNetworkReply*)));

متد send_requset(QUrl)  آور لود میکنیم ( دوباره پیاده سازی میکنیم) .یعنی ما دو تابع send_request  داریم.

  1. void zxMain::send_request(QUrl url)
  2. {
  3.     QNetworkRequest req(url);//url of avatar...
  4.     m_fileDownloader->get(req);
  5. }

و متد downloaded() به شرح زیر است:

  1. void zxMain::downloaded(QNetworkReply *reply)
  2. {
  3.     if(m_file!=NULL)
  4.     {
  5.         delete m_file;
  6.         m_file=NULL;
  7.     }
  8.    if(reply->error()==QNetworkReply::NoError)
  9.    {
  10.     m_file=new QByteArray(reply->readAll());
  11.    }
  12.     show_info();
  13.     ui->btn_showInfo->setEnabled(true);
  14. }

ابتدا در کانستراکتور کلاس m_file=NULL  قرار دهید. دقت نمایید که m_file  از جنس QByteArray می باشد و قرار است در  متد show_info() با استفاده از ابجکت m_file و ابجکت m_jsonData مشخصات مورد نظر را به کاربر نمایش دهیم.

نمایش داده ها دریافت شده در فرم :

نکته: هنگامی که کاربر بر روی کلید نمایش (btn_show) کلیک کرد لازم است تا زمانی که دیتا بطور کامل دریافت نشده این کلید غیرفعال باشد و پس از اینکه دیتا دریافت شد آن را مجددا فعال نماییم:

پس بدین منظور در متد btn_shw() ایتدا کد زیر را وارد کنید :

ui->btn_showInfo->setEnabled(false);

و در متدد downloaded() در خط آخر این شی را مجددا فعال کنیم:

 ui->btn_showInfo->setEnabled(true);

پیاده سازی متد show_info():

  1. Void zxMain::show_info()
  2. {
  3.     ui->lb_name->setText(m_jsonData["name"].toString());
  4.     ui->lb_phone->setText(m_jsonData["phone"].toString());
  5.     ui->lb_brithday->setText(m_jsonData["brithday"].toString());
  6.     QPixmap avatar;
  7.     if(m_file->isEmpty())
  8.     {
  9.         avatar.load(QString(":/img/user.png"));//load default avatar
  10.     }
  11.     else
  12.     {
  13.         avatar.loadFromData(*m_file);//load user avatar from m_file...
  14.     }
  15.     ui->lb_avatar->setPixmap(avatar);
  16. }

در این متد با استفاده از آبجکت m_jsonData رشته های مورد نظر را برای لیبل های موجود در فرم استخراج می کنیم. و عنصر m_file را به یک متغییر از جنس QPixmap  پاس می دهیم و سپس متغییر avatar  را به عنوان pixmap  لیبل lb_avatar تنظیم می کنیم.

چند نکته :

 در فرم طراحی شی le_uPass را انتخاب کنید و از پنجره property editor مقدار echoMode را بر روی password قرار دهید.

در کانستراکتور کلاس طول عرض صفحه را تنظیم کنید و کلید ماکسیمایز را غیر فعال کنید:

   this->setFixedWidth(400)
    this->setFixedHeight(400);

پروژه برنامه نویسی شبکه در محیط برنامه نویسی Qt
پروژه برنامه نویسی شبکه در محیط برنامه نویسی Qt

سورس کامل برنامه :

zxMain.h

  1. #ifndef ZXMAIN_H
  2. #define ZXMAIN_H
  3.  
  4. #include <QMainWindow>
  5. #include <QDebug>
  6.  
  7. #include <QNetworkAccessManager>
  8. #include <QNetworkRequest>
  9. #include <QNetworkReply>
  10. #include <QJsonDocument>
  11. #include <QJsonObject>
  12.  
  13. namespace Ui {
  14. class zxMain;
  15. }
  16.  
  17. class zxMain : public QMainWindow
  18. {
  19.     Q_OBJECT
  20.  
  21. public:
  22.     explicit zxMain(QWidget *parent = 0);    
  23.     ~zxMain();
  24.  
  25.     void show_info();
  26.  
  27. private:
  28.     Ui::zxMain *ui;
  29.     QNetworkAccessManager *m_manager;
  30.     QNetworkAccessManager *m_fileDownloader;
  31.     QJsonObject m_jsonData;
  32.     QByteArray *m_file;
  33.  
  34.     //QNetworkReply *m_reply;
  35.  
  36.     void send_request();
  37.     void send_request(QUrl url);
  38. private slots:
  39.     void btn_show();
  40.     void network_reply(QNetworkReply* reply);
  41.     void downloaded(QNetworkReply* reply);
  42. };
  43.  
  44. #endif // ZXMAIN_H

zxmain.cpp

  1. #include "zxmain.h"
  2. #include "ui_zxmain.h"
  3. #include <QMessageBox>
  4.  
  5. zxMain::zxMain(QWidget *parent) :
  6.     QMainWindow(parent),
  7.     ui(new Ui::zxMain)
  8. {
  9.     ui->setupUi(this);    
  10.     this->setFixedWidth(400);
  11.     this->setFixedHeight(400);
  12.     m_manager=new QNetworkAccessManager();
  13.     m_fileDownloader=new QNetworkAccessManager();
  14.     m_file=NULL;
  15.     connect(ui->btn_showInfo,SIGNAL(clicked(bool)),this,SLOT(btn_show()));
  16.     connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(network_reply(QNetworkReply*)));
  17.     connect(m_fileDownloader,SIGNAL(finished(QNetworkReply*)),this,SLOT(downloaded(QNetworkReply*)));
  18. }
  19.  
  20. zxMain::~zxMain()
  21. {
  22.     delete m_file;
  23.     delete m_fileDownloader;
  24.     delete m_manager;
  25.     delete ui;
  26. }
  27.  
  28. void zxMain::show_info()
  29. {
  30.     ui->lb_name->setText(m_jsonData["name"].toString());
  31.     ui->lb_phone->setText(m_jsonData["phone"].toString());
  32.     ui->lb_brithday->setText(m_jsonData["brithday"].toString());
  33.     QPixmap avatar;
  34.     if(m_file->isEmpty())
  35.     {
  36.         avatar.load(QString(":/img/user.png"));//load default avatar
  37.     }
  38.     else
  39.     {
  40.         avatar.loadFromData(*m_file);//load user avatar from m_file...
  41.     }
  42.     ui->lb_avatar->setPixmap(avatar);
  43. }
  44.  
  45. void zxMain::send_request()
  46. {
  47.     QUrl url(QString("http://localhost:8080/Qt-mrzx_ir/server.php"));
  48.     QNetworkRequest req(url);
  49.     req.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
  50.     QString body="username="+ui->le_uName->text()+"&password="+ui->le_uPass->text();
  51.  
  52.     m_manager->post(req,body.toLatin1());
  53. }
  54.  
  55. void zxMain::send_request(QUrl url)
  56. {
  57.     QNetworkRequest req(url);//url of avatar...
  58.     m_fileDownloader->get(req);
  59. }
  60.  
  61. void zxMain::btn_show()
  62. {
  63.     ui->btn_showInfo->setEnabled(false);
  64.     send_request();
  65. }
  66.  
  67. void zxMain::network_reply(QNetworkReply *reply)
  68. {
  69.     if(reply->error()==QNetworkReply::NoError)
  70.     {
  71.         QString data=(QString)reply->readAll();
  72.         QJsonDocument jsonDoc=QJsonDocument::fromJson(data.toUtf8());
  73.         m_jsonData=jsonDoc.object();
  74.         qDebug()<<data;
  75.         if(m_jsonData["error"].toString()=="noError")
  76.            {
  77.             QString name(m_jsonData["name"].toString()),
  78.                     phone(m_jsonData["phone"].toString()),
  79.                     brithday(m_jsonData["brithday"].toString());
  80.             QUrl avatarUrl=m_jsonData["avatar"].toString();
  81.             send_request(avatarUrl);
  82.         }
  83.         else
  84.             QMessageBox::information(this,"خطا","نام کاربری یا کلمه عبور اشتباه می باشد.");
  85.     }
  86.     else
  87.         QMessageBox::information(this,"خطا",reply->errorString());
  88. }
  89.  
  90. void zxMain::downloaded(QNetworkReply *reply)
  91. {
  92.     if(m_file!=NULL)
  93.     {
  94.         delete m_file;
  95.         m_file=NULL;
  96.     }
  97.    if(reply->error()==QNetworkReply::NoError)
  98.    {
  99.     m_file=new QByteArray(reply->readAll());
  100.    }
  101.     show_info();
  102.     ui->btn_showInfo->setEnabled(true);
  103. }

دانلود سورس کامل پروژه همراه با فایل ها ی سرور از طریق لینک زیر:

مطالب مرتبط

 دیدگاهتان را بنویسید   

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

2 دیدگاه ارائه شده برای "پروژه برنامه نویسی شبکه و ارتباط با سرور در Qt – قسمت دوم"

  1. Avatar Ali گفت:

    سلام
    لینک فایل سورس خرابه
    بی زحمت آپدیت کنین

    1. رضا احمدی رضا احمدی گفت:

      سلام
      لینک فایل بروز شد.