C++ Qt多執行緒 TcpSocket伺服器例項
阿新 • • 發佈:2019-01-24
伺服器: incomming incomming.pro #------------------------------------------------- # # Project created by QtCreator 2016-04-08T09:25:22 # #------------------------------------------------- QT += core gui QT +=network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = incomming TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp \ myserver.cpp \ socketthread.cpp \ mytcpsocket.cpp HEADERS += mainwindow.h \ myserver.h \ socketthread.h \ mytcpsocket.h FORMS += mainwindow.ui mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QTcpSocket; class myserver; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT private: myserver * server; public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H myserver.h #ifndef MYSERVER #define MYSERVER #include<QObject> #include<QTcpServer> #include<QWidget> class myserver :public QTcpServer{ Q_OBJECT public: myserver(QWidget * parent); protected: virtual void incomingConnection(qintptr socketDescriptor); }; //|定義的結束 必須加; #endif // MYSERVER mytcpsocket.h #ifndef MYTCPSOCKET #define MYTCPSOCKET #include<QTcpSocket> class mytcpsocket :public QTcpSocket { Q_OBJECT public: mytcpsocket(QWidget * parent,qintptr p); private slots: void on_discon(); public: void on_connected(); }; #endif // MYTCPSOCKET socketthread.h #ifndef SOCKETTHREAD #define SOCKETTHREAD #include<QThread> #include<QTcpSocket> #include<QWidget> class mytcpsocket; class socketThread :public QThread { private: qintptr ptr; mytcpsocket * socket; public: socketThread(QWidget * parent,qintptr p); protected: virtual void run(); }; #endif // SOCKETTHREAD mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include"myserver.h" #include<QHostAddress> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); this->server=new myserver(this); this->server->listen(QHostAddress::LocalHost,520); } MainWindow::~MainWindow() { delete ui; } myserver.cpp #include"myserver.h" #include<QMessageBox> #include"mytcpsocket.h" #include"socketthread.h" myserver::myserver(QWidget * parent):QTcpServer(parent){ } void myserver::incomingConnection(qintptr socketDescriptor) { QMessageBox::about(0,"提示","有新連線"); socketThread * thread=new socketThread(0,socketDescriptor); thread->start(); /* mytcpsocket * socket=new mytcpsocket(0,socketDescriptor); QThread * thread=new QThread(); socket->moveToThread(thread); thread->start(); */ } mytcpsocket.cpp #include"mytcpsocket.h" #include<QByteArray> #include<QDataStream> #include<QString> #include<QMessageBox> #include<QDebug> mytcpsocket::mytcpsocket(QWidget *parent,qintptr p):QTcpSocket(0) { //connect(this,SIGNAL(),this,SLOT(on_connected())); this->setSocketDescriptor(p); this->on_connected(); this->connect(this,SIGNAL(disconnected()),this,SLOT(on_discon())); } void mytcpsocket::on_connected() { QByteArray arr; QDataStream dts(&arr,QIODevice::WriteOnly); dts<<QString("這是資料"); this->write(arr); //QMessageBox::about(0,"x","傳送成功!"); qDebug()<<"傳送成功"; } void mytcpsocket::on_discon() { qDebug()<<"有一個客戶端斷開!"; } socketthread.cpp #include"socketthread.h" #include<QString> #include<QByteArray> #include<QDataStream> #include<QMessageBox> #include<QDebug> #include"mytcpsocket.h" socketThread::socketThread(QWidget *parent,qintptr p):QThread(parent) { qDebug()<<"QThread建構函式依然在 舊執行緒"; this->ptr=p; } void socketThread::run(){ /*1.QObject->moveToThread(Thread *)會把一個Qt物件移動到一個新執行緒中執行 預設在run()中呼叫了 exec()這樣 run()執行完後不會 * 直接關閉 執行緒 還會讓它 進入訊息迴圈 直到呼叫了 結束 槽 * 2.QtcpSocket 的write()函式是非同步的 也就是 呼叫了 後不會立即 傳送資料,它會直接往下執行 直到run()的尾部,如果run()沒有 * 呼叫exec()進行訊息迴圈等待,那麼 這個執行緒 直接就結束了,不會再發送。(傳送資料失敗) *3.如果在run()中呼叫了 exec()(傳送成功) *4.如果在 write(QByteArray);後面加一句 socket->waitForBytesWritten();這裡就會阻塞等待 直到資料開始傳送,這樣 * 不需要exec()在 執行緒結束之前直接就傳送完了 *socket->waitForConnected() * socket->waitForDisconnected() * socket->waitForReadyRead()都是一個道理 */ qDebug()<<"開始新執行緒"; /* QTcpSocket * socket=new QTcpSocket(); socket->setSocketDescriptor(this->ptr); QByteArray arr; QDataStream dts(&arr,QIODevice::WriteOnly); dts<<QString("這是資料"); socket->write(arr); */ mytcpsocket * socket=new mytcpsocket(0,this->ptr); socket->waitForBytesWritten(); // this->exec(); /* 1. 連線伺服器 m_tcpSocket->connectToHost("127.0.0.1", 9877); connected = m_tcpSocket->waitForConnected(); 只有使用waitForConnected()後,QTcpSocket才真正嘗試連線伺服器,並返回是否連線的結果。 2. 寫資料 m_tcpSocket->write(str.toStdString().c_str(), strlen(str.toStdString().c_str())); m_tcpSocket->waitForBytesWritten(); 當使用waitForBytesWritten()後,QTcpSocket才真正傳送資料。 m_tcpSocket->write(str1.toStdString().c_str(), strlen(str1.toStdString().c_str())); m_tcpSocket->write(str2.toStdString().c_str(), strlen(str2.toStdString().c_str())); 的結果是傳送了str1str2 3. 斷開與伺服器的連線 m_tcpSocket->disconnectFromHost() m_tcpSocket->waitForDisconnected() 4. 善於使用QTcpSocket的SIGNAL:connected(), disconnected(), error(QAbstractSocket::SocketError) 配合自定義私有開關變數bool connected, QTimer 可以實現自動重連線等邏輯。 */ } main.cpp #include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } /***********************/ 客戶端 useincomming useincomming.pro #------------------------------------------------- # # Project created by QtCreator 2016-04-08T09:36:28 # #------------------------------------------------- QT += core gui QT +=network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = useincomming TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp HEADERS += mainwindow.h FORMS += mainwindow.ui mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QTcpSocket; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: QTcpSocket * socket; private: Ui::MainWindow *ui; private slots: void on_readyread(); void on_conn(); }; #endif // MAINWINDOW_H mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include<QTcpSocket> #include<QHostAddress> #include<QString> #include<QByteArray> #include<QDataStream> #include<QMessageBox> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); this->socket=new QTcpSocket(this); this->socket->connectToHost(QHostAddress::LocalHost,520); connect(this->socket,SIGNAL(connected()),this,SLOT(on_conn())); connect(this->socket,SIGNAL(readyRead()),this,SLOT(on_readyread())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_readyread() { QMessageBox::about(this,"提示","開始接受"); QByteArray array=this->socket->readAll(); QDataStream dts(&array,QIODevice::ReadOnly); QString data; dts>>data; QMessageBox::about(this,"提示",data); } void MainWindow::on_conn() { QMessageBox::about(this,"提示","連線成功"); } main.cpp #include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }