C++ Qt多线程 TcpSocket服务器实例

 

C++ Qt多线程 TcpSocket服务器实例

  5276人阅读  评论(2)  收藏  举报
  分类:
  
  
  1. 服务器:  
  2. incomming  
  3. incomming.pro  
  4. #-------------------------------------------------  
  5. #  
  6. # Project created by QtCreator 2016-04-08T09:25:22  
  7. #  
  8. #-------------------------------------------------  
  9.   
  10.   
  11. QT       += core gui  
  12. QT        +=network  
  13. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets  
  14.   
  15.   
  16. TARGET = incomming  
  17. TEMPLATE = app  
  18.   
  19.   
  20.   
  21.   
  22. SOURCES += main.cpp\  
  23.         mainwindow.cpp \  
  24.     myserver.cpp \  
  25.     socketthread.cpp \  
  26.     mytcpsocket.cpp  
  27.   
  28.   
  29. HEADERS  += mainwindow.h \  
  30.     myserver.h \  
  31.     socketthread.h \  
  32.     mytcpsocket.h  
  33.   
  34.   
  35. FORMS    += mainwindow.ui  
  36.   
  37.   
  38.   
  39.   
  40. mainwindow.h  
  41. #ifndef MAINWINDOW_H  
  42. #define MAINWINDOW_H  
  43.   
  44.   
  45. #include <QMainWindow>  
  46. class QTcpSocket;  
  47. class myserver;  
  48. namespace Ui {  
  49. class MainWindow;  
  50. }  
  51.   
  52.   
  53. class MainWindow : public QMainWindow  
  54. {  
  55.     Q_OBJECT  
  56. private:  
  57.   myserver * server;  
  58. public:  
  59.     explicit MainWindow(QWidget *parent = 0);  
  60.     ~MainWindow();  
  61.   
  62.   
  63. private:  
  64.     Ui::MainWindow *ui;  
  65. };  
  66.   
  67.   
  68. #endif // MAINWINDOW_H  
  69.   
  70.   
  71.   
  72. myserver.h  
  73. #ifndef MYSERVER  
  74. #define MYSERVER  
  75. #include<QObject>  
  76. #include<QTcpServer>  
  77. #include<QWidget>  
  78. class myserver :public QTcpServer{  
  79.     Q_OBJECT  
  80. public:  
  81.     myserver(QWidget * parent);  
  82. protected:  
  83.     virtual void incomingConnection(qintptr socketDescriptor);  
  84.   
  85.   
  86. };  
  87. //|定义的结束 必须加;  
  88. #endif // MYSERVER  
  89.   
  90.   
  91.   
  92.   
  93. mytcpsocket.h  
  94. #ifndef MYTCPSOCKET  
  95. #define MYTCPSOCKET  
  96. #include<QTcpSocket>  
  97.   
  98.   
  99. class mytcpsocket :public QTcpSocket  
  100. {  
  101.     Q_OBJECT  
  102. public:  
  103.     mytcpsocket(QWidget * parent,qintptr p);  
  104. private slots:  
  105.     void on_discon();  
  106.   
  107.   
  108. public:  
  109.     void on_connected();  
  110.   
  111.   
  112. };  
  113. #endif // MYTCPSOCKET  
  114.   
  115.   
  116.   
  117.   
  118. socketthread.h  
  119.   
  120.   
  121. #ifndef SOCKETTHREAD  
  122. #define SOCKETTHREAD  
  123. #include<QThread>  
  124. #include<QTcpSocket>  
  125. #include<QWidget>  
  126. class mytcpsocket;  
  127. class socketThread :public QThread  
  128. {  
  129. private:  
  130.     qintptr ptr;  
  131.     mytcpsocket * socket;  
  132. public:  
  133.     socketThread(QWidget * parent,qintptr p);  
  134. protected:  
  135.     virtual void run();  
  136.   
  137.   
  138.   
  139.   
  140. };  
  141. #endif // SOCKETTHREAD  
  142.   
  143.   
  144.   
  145.   
  146. mainwindow.cpp  
  147. #include "mainwindow.h"  
  148. #include "ui_mainwindow.h"  
  149. #include"myserver.h"  
  150. #include<QHostAddress>  
  151.   
  152.   
  153. MainWindow::MainWindow(QWidget *parent) :  
  154.     QMainWindow(parent),  
  155.     ui(new Ui::MainWindow)  
  156. {  
  157.     ui->setupUi(this);  
  158.     this->server=new myserver(this);  
  159.     this->server->listen(QHostAddress::LocalHost,520);  
  160. }  
  161.   
  162.   
  163. MainWindow::~MainWindow()  
  164. {  
  165.     delete ui;  
  166. }  
  167.   
  168.   
  169. myserver.cpp  
  170. #include"myserver.h"  
  171. #include<QMessageBox>  
  172. #include"mytcpsocket.h"  
  173. #include"socketthread.h"  
  174. myserver::myserver(QWidget * parent):QTcpServer(parent){  
  175.   
  176.   
  177. }  
  178. void myserver::incomingConnection(qintptr socketDescriptor)  
  179. {  
  180.     QMessageBox::about(0,"提示","有新连接");  
  181.      socketThread * thread=new socketThread(0,socketDescriptor);  
  182.     thread->start();  
  183.   
  184.   
  185.     /* 
  186.     mytcpsocket * socket=new mytcpsocket(0,socketDescriptor); 
  187.     QThread * thread=new QThread(); 
  188.     socket->moveToThread(thread); 
  189.     thread->start(); 
  190.     */  
  191.   
  192.   
  193.   
  194.   
  195. }  
  196.   
  197.   
  198. mytcpsocket.cpp  
  199. #include"mytcpsocket.h"  
  200. #include<QByteArray>  
  201. #include<QDataStream>  
  202. #include<QString>  
  203. #include<QMessageBox>  
  204. #include<QDebug>  
  205. mytcpsocket::mytcpsocket(QWidget *parent,qintptr p):QTcpSocket(0)  
  206. {  
  207.   
  208.   
  209.   //connect(this,SIGNAL(),this,SLOT(on_connected()));  
  210.     this->setSocketDescriptor(p);  
  211.     this->on_connected();  
  212.  this->connect(this,SIGNAL(disconnected()),this,SLOT(on_discon()));  
  213.   
  214.   
  215. }  
  216. void mytcpsocket::on_connected()  
  217. {  
  218.   
  219.   
  220.     QByteArray arr;  
  221.     QDataStream dts(&arr,QIODevice::WriteOnly);  
  222.     dts<<QString("这是数据");  
  223.     this->write(arr);  
  224.     //QMessageBox::about(0,"x","发送成功!");  
  225.     qDebug()<<"发送成功";  
  226.   
  227.   
  228. }  
  229. void mytcpsocket::on_discon()  
  230. {  
  231.     qDebug()<<"有一个客户端断开!";  
  232. }  
  233.   
  234.   
  235. socketthread.cpp  
  236. #include"socketthread.h"  
  237. #include<QString>  
  238. #include<QByteArray>  
  239. #include<QDataStream>  
  240. #include<QMessageBox>  
  241. #include<QDebug>  
  242. #include"mytcpsocket.h"  
  243. socketThread::socketThread(QWidget *parent,qintptr p):QThread(parent)  
  244. {  
  245.   
  246.   
  247.     qDebug()<<"QThread构造函数依然在 旧线程";  
  248.     this->ptr=p;  
  249. }  
  250.   
  251.   
  252. void socketThread::run(){  
  253.   
  254.   
  255.     /*1.QObject->moveToThread(Thread *)会把一个Qt对象移动到一个新线程中运行 默认在run()中调用了 exec()这样 run()执行完后不会 
  256.      * 直接关闭 线程 还会让它 进入消息循环 直到调用了 结束 槽 
  257.      * 2.QtcpSocket 的write()函数是异步的 也就是 调用了 后不会立即 发送数据,它会直接往下执行 直到run()的尾部,如果run()没有 
  258.      * 调用exec()进行消息循环等待,那么 这个线程 直接就结束了,不会再发送。(发送数据失败) 
  259.      *3.如果在run()中调用了 exec()(发送成功) 
  260.      *4.如果在 write(QByteArray);后面加一句 socket->waitForBytesWritten();这里就会阻塞等待 直到数据开始发送,这样 
  261.      * 不需要exec()在 线程结束之前直接就发送完了 
  262.      *socket->waitForConnected() 
  263.      * socket->waitForDisconnected() 
  264.      * socket->waitForReadyRead()都是一个道理 
  265.      */  
  266.     qDebug()<<"开始新线程";  
  267.    /* QTcpSocket * socket=new QTcpSocket(); 
  268.     socket->setSocketDescriptor(this->ptr); 
  269.  
  270.  
  271.     QByteArray arr; 
  272.     QDataStream dts(&arr,QIODevice::WriteOnly); 
  273.     dts<<QString("这是数据"); 
  274.     socket->write(arr); 
  275.     */  
  276.     mytcpsocket * socket=new mytcpsocket(0,this->ptr);  
  277.     socket->waitForBytesWritten();  
  278.   // this->exec();  
  279.     /* 
  280. 1.  连接服务器 
  281. m_tcpSocket->connectToHost("127.0.0.1", 9877); 
  282. connected = m_tcpSocket->waitForConnected(); 
  283. 只有使用waitForConnected()后,QTcpSocket才真正尝试连接服务器,并返回是否连接的结果。 
  284.  
  285.  
  286. 2. 写数据 
  287. m_tcpSocket->write(str.toStdString().c_str(), strlen(str.toStdString().c_str())); 
  288. m_tcpSocket->waitForBytesWritten(); 
  289. 当使用waitForBytesWritten()后,QTcpSocket才真正发送数据。 
  290. m_tcpSocket->write(str1.toStdString().c_str(), strlen(str1.toStdString().c_str())); 
  291. m_tcpSocket->write(str2.toStdString().c_str(), strlen(str2.toStdString().c_str())); 
  292. 的结果是发送了str1str2 
  293.  
  294.  
  295. 3. 断开与服务器的连接 
  296. m_tcpSocket->disconnectFromHost() 
  297. m_tcpSocket->waitForDisconnected() 
  298.  
  299.  
  300. 4. 善于使用QTcpSocket的SIGNAL:connected(), disconnected(), error(QAbstractSocket::SocketError) 
  301.     配合自定义私有开关变量bool connected, QTimer 
  302.    可以实现自动重连接等逻辑。 
  303.  
  304.  
  305.       */  
  306. }  
  307.   
  308.   
  309. main.cpp  
  310. #include "mainwindow.h"  
  311. #include <QApplication>  
  312.   
  313.   
  314. int main(int argc, char *argv[])  
  315. {  
  316.     QApplication a(argc, argv);  
  317.     MainWindow w;  
  318.     w.show();  
  319.   
  320.   
  321.     return a.exec();  
  322. }  
  323.   
  324.   
  325.   
  326.   
  327.   
  328.   
  329.   
  330.   
  331.   
  332.   
  333.   
  334.   
  335. /***********************/  
  336.   
  337.   
  338.   
  339.   
  340.   
  341.   
  342.   
  343.   
  344.   
  345.   
  346. 客户端  
  347. useincomming  
  348. useincomming.pro  
  349. #-------------------------------------------------  
  350. #  
  351. # Project created by QtCreator 2016-04-08T09:36:28  
  352. #  
  353. #-------------------------------------------------  
  354.   
  355.   
  356. QT       += core gui  
  357. QT       +=network  
  358. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets  
  359.   
  360.   
  361. TARGET = useincomming  
  362. TEMPLATE = app  
  363.   
  364.   
  365.   
  366.   
  367. SOURCES += main.cpp\  
  368.         mainwindow.cpp  
  369.   
  370.   
  371. HEADERS  += mainwindow.h  
  372.   
  373.   
  374. FORMS    += mainwindow.ui  
  375.   
  376.   
  377. mainwindow.h  
  378. #ifndef MAINWINDOW_H  
  379. #define MAINWINDOW_H  
  380.   
  381.   
  382. #include <QMainWindow>  
  383. class QTcpSocket;  
  384. namespace Ui {  
  385. class MainWindow;  
  386. }  
  387.   
  388.   
  389. class MainWindow : public QMainWindow  
  390. {  
  391.     Q_OBJECT  
  392.   
  393.   
  394. public:  
  395.     explicit MainWindow(QWidget *parent = 0);  
  396.     ~MainWindow();  
  397. private:  
  398.     QTcpSocket * socket;  
  399. private:  
  400.     Ui::MainWindow *ui;  
  401. private slots:  
  402.     void on_readyread();  
  403.     void on_conn();  
  404. };  
  405.   
  406.   
  407. #endif // MAINWINDOW_H  
  408.   
  409.   
  410. mainwindow.cpp  
  411. #include "mainwindow.h"  
  412. #include "ui_mainwindow.h"  
  413. #include<QTcpSocket>  
  414. #include<QHostAddress>  
  415. #include<QString>  
  416. #include<QByteArray>  
  417. #include<QDataStream>  
  418. #include<QMessageBox>  
  419. MainWindow::MainWindow(QWidget *parent) :  
  420.     QMainWindow(parent),  
  421.     ui(new Ui::MainWindow)  
  422. {  
  423.     ui->setupUi(this);  
  424.     this->socket=new QTcpSocket(this);  
  425.     this->socket->connectToHost(QHostAddress::LocalHost,520);  
  426.     connect(this->socket,SIGNAL(connected()),this,SLOT(on_conn()));  
  427.     connect(this->socket,SIGNAL(readyRead()),this,SLOT(on_readyread()));  
  428. }  
  429.   
  430.   
  431. MainWindow::~MainWindow()  
  432. {  
  433.     delete ui;  
  434. }  
  435. void MainWindow::on_readyread()  
  436. {  
  437.     QMessageBox::about(this,"提示","开始接受");  
  438.     QByteArray array=this->socket->readAll();  
  439.     QDataStream dts(&array,QIODevice::ReadOnly);  
  440.     QString data;  
  441.     dts>>data;  
  442.     QMessageBox::about(this,"提示",data);  
  443.   
  444.   
  445. }  
  446. void MainWindow::on_conn()  
  447. {  
  448.     QMessageBox::about(this,"提示","连接成功");  
  449. }  
  450.   
  451.   
  452. main.cpp  
  453. #include "mainwindow.h"  
  454. #include <QApplication>  
  455.   
  456.   
  457. int main(int argc, char *argv[])  
  458. {  
  459.     QApplication a(argc, argv);  
  460.     MainWindow w;  
  461.     w.show();  
  462.   
  463.   
  464.     return a.exec();  
  465. }  
实现一个多线程TCP服务器,可以使用Qt的网络模块和多线程模块。 以下是一个简单的示例代码: ```c++ #include <QtNetwork> #include <QtCore> class TcpServer : public QObject { Q_OBJECT public: TcpServer(QObject *parent = nullptr) : QObject(parent) { server = new QTcpServer(this); connect(server, SIGNAL(newConnection()), this, SLOT(newConnection())); } void listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) { server->listen(address, port); } private slots: void newConnection() { QTcpSocket *socket = server->nextPendingConnection(); if (socket) { QThread *thread = new QThread(this); TcpSocketWorker *worker = new TcpSocketWorker(socket); worker->moveToThread(thread); connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(thread, SIGNAL(started()), worker, SLOT(process())); connect(worker, SIGNAL(finished()), thread, SLOT(quit())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(worker, SIGNAL(error(QString)), this, SLOT(socketError(QString))); thread->start(); } } void socketError(const QString &errorString) { qDebug() << errorString; } private: QTcpServer *server; }; class TcpSocketWorker : public QObject { Q_OBJECT public: TcpSocketWorker(QTcpSocket *socket, QObject *parent = nullptr) : QObject(parent), socket(socket) { connect(socket, SIGNAL(readyRead()), this, SLOT(read())); connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); } public slots: void process() { qDebug() << "New connection from" << socket->peerAddress().toString() << ":" << socket->peerPort(); // Process the data here } void read() { QByteArray data = socket->readAll(); // Process the data here } void disconnected() { qDebug() << "Connection closed by" << socket->peerAddress().toString() << ":" << socket->peerPort(); emit finished(); } void error(QAbstractSocket::SocketError error) { QString errorString = socket->errorString(); qDebug() << "Socket error:" << errorString; emit error(errorString); } signals: void finished(); void error(const QString &errorString); private: QTcpSocket *socket; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); TcpServer server; server.listen(QHostAddress::Any, 1234); return a.exec(); } #include "main.moc" ``` 这个示例代码中,TcpServer类作为服务器端的入口点,监听来自客户端的连接请求。一旦收到连接请求,TcpServer会在一个新的线程中为该客户端创建一个TcpSocketWorker对象,并将QTcpSocket对象移动到该线程中进行处理。 TcpSocketWorker类是一个QObject类,它处理来自客户端的数据和连接状态变化。在process()槽函数中,可以处理来自客户端的数据。在read()槽函数中,可以读取来自客户端的数据。在disconnected()槽函数中,可以处理连接关闭事件。在error()槽函数中,可以处理socket错误事件。 注意:在处理来自客户端的数据时,可能需要使用线程安全的数据结构和算法来保证线程安全。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值