C++ Qt多线程 TcpSocket服务器实例
服务器: 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(); }