QTsocket网络编程
目錄
1、開發工具:VS + QT
1.1 引用網絡模塊
1.1.1 QT的引用如下:
1.1.2 VS引用如下:
2、編寫服務器(QTCPServer)?
2.1 準備工作/連接工作
2.2 發送或者接受信息
3、編寫客戶端(QTcpSocket)
3.1 準備工作/連接工作
3.2 發送或者接受數據?
4、編寫過程中遇到的問題
4.1 中文亂碼問題
4.2 socket傳輸為空值問題
5、運用socket進行業務處理
5.1 客戶端代碼
5.1.1 客戶端向服務器發送業務
5.1.2 客戶端接受服務器回應
5.2 服務器代碼
1、開發工具:VS + QT
使用VS或者使用QT本身的代碼編輯器其實是一樣的。只是引用QT的網絡模塊的時候會有一些區別。
1.1 引用網絡模塊
1.1.1 QT的引用如下:
在qmake項目文件中添加:
QT += network1.1.2 VS引用如下:
右鍵點擊該VS項目,選擇QT
?點擊QT Project Settings,
在General的屬性列中找到QT Modules,
點擊下拉框找到Select Moudles并點擊,然后勾選Network即可。
2、編寫服務器(QTCPServer)?
2.1 準備工作/連接工作
首先先引入對應的庫文件
#include <qtcpserver.h> #include <qtcpsocket.h>在頭文件中創建QTcpServer和QTcpSocket的全局變量
QTcpServer* server; // 服務器對象 QTcpSocket* socket;//與客戶端進行發送接受信息對象在構造器中實例化server對象并且開始監聽客戶端傳來的socket對象信息?
server = new QTcpServer(this);//創建一個服務器對象 server->listen(QHostAddress::Any, 8080); //開始監聽網絡地址以及端口號2.2 發送或者接受信息
//當server檢測到有socket申請連接并且連接成功的時候,會發出newConnection信號并且執行下面的邏輯 connect(server, &QTcpServer::newConnection, this, [=]() {socket = server->nextPendingConnection(); //得到一個用于通信的套接字對象//往客戶段中發送信息socket->write("server");//socket的write方法其實是有幾個重載方法的,如果為了方便,可以直接用QString類型的變量作為參數。//當有數據可以接受,socket對象發出信號readyReadconnect(socket, &QTcpSocket::readyRead, this, [=](){QString data = socket->readAll();//讀取客戶端傳來的數據qDebug() << "客戶端傳來的數據" << data;//將數據寫到客戶端中});//斷開連接connect(socket, &QTcpSocket::disconnected, this, [=](){socket->close();socket->deleteLater();//釋放指向的內存qDebug() << "結束服務器";});});//server對象檢測到有socket對象申請連接的時候,會調用listenNews方法3、編寫客戶端(QTcpSocket)
3.1 準備工作/連接工作
首先引入對應的庫文件
#include <qtcpsocket.h> #include <qhostaddress.h>在頭文件中創建全局變量QTcpSocket
QTcpSocket* socket;?在構造器中實例化socket對象并且建立連接
socket = new QTcpSocket(this);//實例化一個socket對象 socket->connectToHost(QHostAddress("127.0.0.1"), 8080); //可以通過cmd命令窗口輸入命令ipconfig進行查看服務器電腦的ip(或者你知道服務器的ip也可以)。如果是在本機運行,則IP地址可以輸入默認127.0.0.13.2 發送或者接受數據?
//當socket發送有內容可讀的信號的時候,實現以下槽函數(在該函數接受socket對象的內容)connect(socket, &QTcpSocket::readyRead, this, [=](){QString messageServer = socket->readAll();//接受服務器傳來的內容qDebug() << messageServer;//將數據寫到服務器中socket->write("我是客戶端");//socket的write方法其實是有幾個重載方法的,如果為了方便,可以直接用QString類型的變量作為參數。});//當socket發送斷開連接信號的時候,實現以下槽函數connect(socket, &QTcpSocket::disconnected, this, [=](){//socket->close();qDebug() << "斷開連接";//ui.talk->append("斷開連接");//socket->deleteLater();//釋放指向的內存});//當socket發送連接成功信號的時候,實現以下槽函數connect(socket, &QTcpSocket::connected, this, [=](){qDebug() << "連接成功";});至此,簡單的一個QTsocket通信就已經實現,讀者在運用的時候注意發送以及接受信息的邏輯即可。?
4、編寫過程中遇到的問題
4.1 中文亂碼問題
1、可以在頭文件中加入該代碼
#pragma execution_character_set("utf-8")2、可以用QString自帶的方法
QString::fromLocal8Bit("在這添加你的中文")?4.2 socket傳輸為空值問題
這個問題是我在開發一個項目的時候遇到,當時我的情況是在主窗口A先建立與服務器的連接,然后又打開了一個新窗口B,在B窗口中又建立了與服務器的連接,結果使用完B窗口的socket之后,返回到窗口A,發現窗口A的socket的write函數將要傳輸的內容傳輸到服務器中變成空值。
解決方法:其實也很簡單,在每一次建立新的socket連接時候,將舊的socket先關閉。也就是說我要先關閉A的socket連接,使用socket->close()函數,然后再建立B窗口的socket連接,最后再關閉B窗口的socket連接。返回到A窗口之后,再重新建立一次新的socket連接。
這樣問題就解決了。
除此之外,我還嘗試了將socket對象設置為全工程的一個全局對象,但是也無法解決這個問題。
如果運用多線程的技術應該也是可以解決這個問題,但有待讀者去檢驗。
5、運用socket進行業務處理
在此只說明關于字符串的一些業務處理,對于視頻流或者圖片等,有待讀者自行研究(但其實也是大同小異)。
以下借助實現系統賬號密碼的增刪改查例子來說明:
問題一:服務器怎么知道客戶端正在處理什么業務?
基本邏輯就是,在客戶端將傳輸給服務器的字符串上加上分隔符,信息傳輸到服務器時,服務器將這些字符串進行分割提取,從中拿到業務信息、賬號、密碼等內容。
5.1 客戶端代碼
5.1.1 客戶端向服務器發送業務
代碼中的QString對象 messageClient 就是用來存放客戶端業務的標識符;“-” 就是用來識別的信息分隔符
/**********************如果勾選的是添加按鈕**************************/if (ui.add->isChecked() == true){QString accound = ui.account->text(); //記錄輸入的賬號QString password = ui.password->text();//記錄輸入的密碼messageClient = "accoundAdd";//客戶端添加賬號業務標識符//先判斷賬號密碼是否為空if (accound == NULL || password == NULL)//如果為空則發出警告{QMessageBox::information(this, QString::fromLocal8Bit("添加賬號"), QString::fromLocal8Bit("賬號或者密碼不可以為空,請重新輸入"));}else//如果不為空則將數據傳輸到服務器{socket->write(messageClient.toUtf8() + "-" + accound.toUtf8() + "-" + password.toUtf8());//將數據傳輸到服務器中}}/**********************如果勾選的是刪除按鈕**************************/if (ui.delete_2->isChecked() == true){QString accound = ui.account->text();//獲取賬號文本框的信息QString password = "null";//將密碼置為“空”messageClient = "accoundDelete";//客戶端刪除賬號業務標識符if (accound != NULL)//判斷是否為空{//如果不為空則將數據傳輸到服務器socket->write(messageClient.toUtf8() + "-" + accound.toUtf8() + "-" + password.toUtf8());//將數據傳輸到服務器中}else{QMessageBox::information(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("賬號不可以為空"));}}/**********************如果勾選的是修改按鈕**************************/if (ui.change->isChecked() == true){QString accound = ui.account->text(); //記錄管理員輸入的賬號QString password = ui.newpassword->text();//記錄管理員輸入的密碼messageClient = "accoundChange";//客戶端修改賬號業務標識符//先判斷賬號密碼是否為空if (accound == NULL || password == NULL){QMessageBox::information(this, QString::fromLocal8Bit("修改密碼"), QString::fromLocal8Bit("賬號或者新密碼不可以為空,請重新輸入"));}else //賬號和新密碼都不為空{socket->write(messageClient.toUtf8() + "-" + accound.toUtf8() + "-" + password.toUtf8());//將數據傳輸到服務器中}}5.1.2 客戶端接受服務器回應
socket = new QTcpSocket(this); socket->connectToHost(QHostAddress("127.0.0.1"), 8080);//當socket發送有內容可讀的信號的時候,實現以下槽函數(在該函數接受socket對象的內容) connect(socket, &QTcpSocket::readyRead, this, [=](){messageServer = socket->readAll();//接受服務器發送的信息qDebug() << messageServer;/******************************查找*********************************/if (QString::localeAwareCompare(messageServer, "SearchSuccess") == 0){QMessageBox::information(this, "", QString::fromLocal8Bit("登錄成功"));socket->close();}if (QString::localeAwareCompare(messageServer, "SearchFail") == 0){QMessageBox::information(this, "", QString::fromLocal8Bit("賬號與密碼不匹配"));}/******************************添加*********************************/if (QString::localeAwareCompare(messageServer, "addSuccess") == 0){QMessageBox::information(this, QString::fromLocal8Bit("添加賬號"), QString::fromLocal8Bit("添加成功"));socket->close()}if (QString::localeAwareCompare(messageServer, "addFail") == 0){QMessageBox::information(this, QString::fromLocal8Bit("添加賬號"), QString::fromLocal8Bit("添加失敗"));}if (QString::localeAwareCompare(messageServer, "accoundRepeat") == 0){QMessageBox::information(this, QString::fromLocal8Bit("添加賬號"), QString::fromLocal8Bit("該賬戶已經存在,請重新輸入"));}/******************************刪除***********************************/if (QString::localeAwareCompare(messageServer, "deleteSuccess") == 0){QMessageBox::information(this, QString::fromLocal8Bit("刪除賬號"), QString::fromLocal8Bit("刪除成功"));socket->close();}if (QString::localeAwareCompare(messageServer, "deleteFail") == 0){QMessageBox::information(this, QString::fromLocal8Bit("刪除賬號"), QString::fromLocal8Bit("刪除失敗"));}if (QString::localeAwareCompare(messageServer, "delete-accoundNoFound") == 0){QMessageBox::information(this, QString::fromLocal8Bit("刪除賬號"), QString::fromLocal8Bit("刪除失敗,賬號沒有找到"));}/******************************修改***********************************/if (QString::localeAwareCompare(messageServer, "changeSuccess") == 0){QMessageBox::information(this, QString::fromLocal8Bit("修改賬號"), QString::fromLocal8Bit("修改成功"));socket->close();}if (QString::localeAwareCompare(messageServer, "changeFail") == 0){QMessageBox::information(this, QString::fromLocal8Bit("修改賬號"), QString::fromLocal8Bit("修改失敗"));}if (QString::localeAwareCompare(messageServer, "change-accoundNoFound") == 0){QMessageBox::information(this, QString::fromLocal8Bit("修改賬號"), QString::fromLocal8Bit("修改失敗,賬號沒有找到"));}});connect(socket, &QTcpSocket::disconnected, this, [=](){qDebug() << QString::fromLocal8Bit("**斷開連接");//ui.talk->append("斷開連接");//socket->deleteLater();//釋放指向的內存});connect(socket, &QTcpSocket::connected, this, [=](){qDebug() << QString::fromLocal8Bit("**連接成功");});5.2 服務器代碼
QStringList對象的 list 的第一個元素即list[0]為客戶端目前要執行的業務信息,利用字符串匹配就可以在服務器中處理相關的信息。
該例子涉及到了一些數據庫語句,讀者可以忽略,并不影響整體的傳輸邏輯。
server = new QTcpServer(this);//創建一個服務器對象 server->listen(QHostAddress::Any, port); //開始監聽網絡地址以及端口號//當連接成功的時候 connect(server, &QTcpServer::newConnection, this, [=]() {socket = server->nextPendingConnection(); //得到一個用于通信的套接字對象 //檢測是否準備接受數據,當有數據可以接受,則發出信號 readyReadconnect(socket, &QTcpSocket::readyRead, this, [=](){QString data = socket->readAll();//讀取客戶端傳來的數據qDebug() << "客戶端傳來的數據" << data;QStringList list = data.split("-");//QString字符串分割函數,將業務信息、賬號和密碼等提取出來//查找,用于登錄過程if (QString::localeAwareCompare(list[0],"login") == 0){QString username1 = list[1];QString password1 = list[2];qDebug() << "賬號:" << username1;qDebug() << "密碼:" << password1;QSqlQuery sql; // 數據庫對象QString istrue = QString("select * from user1 where username = '%1' and password = '%2'").arg(username1).arg(password1);sql.exec(istrue);if (sql.next() || (username1 == "admin" && password1 == "admin")){socket->write("SearchSuccess");qDebug() << "查找成功";}else{socket->write("SearchFail");qDebug() << "查找失敗";}}//如果客戶端進行添加賬號業務if (QString::localeAwareCompare(list[0], "accoundAdd") == 0){QString accound = list[1];QString password = list[2];qDebug() << messageClient;QSqlQuery sql; // 數據庫對象//第一步、先查重istrue = QString("select * from user1 where username = '%1'").arg(accound);sql.exec(istrue);if (sql.next()){socket->write("accoundRepeat");//賬號重復qDebug() << "賬號重復";}else{//如果數據庫沒有該賬號,則進行添加istrue = QString("insert into user1(username,password) values('%1','%2')").arg(accound).arg(password);sql.exec(istrue);//檢查是否插入成功istrue = QString("select * from user1 where username = '%1' and password = '%2'").arg(accound).arg(password);sql.exec(istrue);if (sql.next()){socket->write("addSuccess");qDebug() << "添加成功";}else{socket->write("addFail");qDebug() << "添加失敗";}}}//客戶端進行刪除賬號業務if (QString::localeAwareCompare(list[0], "accoundDelete") == 0){QString accound = list[1];QString password = list[2];qDebug() << messageClient;QSqlQuery sql; // 數據庫對象//想刪除 先查詢istrue = QString("select * from user1 where username = '%1'").arg(accound);sql.exec(istrue);if (sql.next())//如果存在{istrue = QString("delete from user1 where username = '%1'").arg(accound);sql.exec(istrue);//查看是否刪除成功istrue = QString("select * from user1 where username = '%1'").arg(accound);sql.exec(istrue);if (sql.next()){socket->write("deleteFail");qDebug() << "刪除失敗";}else{socket->write("deleteSuccess");qDebug() << "刪除成功";}}else{socket->write("delete-accoundNoFound");qDebug() << "賬號不存在";}}//客戶端進行修改賬號密碼業務if (QString::localeAwareCompare(list[0], "accoundChange") == 0){QString accound = list[1];QString password = list[2];qDebug() << messageClient;QSqlQuery sql; // 數據庫對象istrue = QString("select * from user1 where username = '%1'").arg(accound);sql.exec(istrue);if (sql.next())//如果存在{istrue = QString("update user1 set password = '%1' where username = '%2'").arg(password).arg(accound);sql.exec(istrue);//查看是否修改成功istrue = QString("select * from user1 where username = '%1' and password = '%2'").arg(accound).arg(password);sql.exec(istrue);if (sql.next()){socket->write("changeSuccess");qDebug() << "修改成功";}else{socket->write("changeFail");qDebug() << "修改失敗";}}else{socket->write("change-accoundNoFound");qDebug() << "賬號不存在";}}}); });總結
以上是生活随笔為你收集整理的QTsocket网络编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微机总线地址,物理地址 ,虚拟地址
- 下一篇: C++基础( C++初识、数据类型、运算