├── .gitignore ├── QtMultiThreadTcpServer.pro ├── README.md ├── dialog.cpp ├── dialog.h ├── dialog.ui ├── main.cpp ├── mysocket.cpp ├── mysocket.h ├── server.cpp ├── server.h ├── serverthread.cpp └── serverthread.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.user 3 | -------------------------------------------------------------------------------- /QtMultiThreadTcpServer.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2016-03-07T20:38:29 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui network 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = QtMultiThreadTcpServer 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | dialog.cpp \ 17 | serverthread.cpp \ 18 | server.cpp \ 19 | mysocket.cpp 20 | 21 | HEADERS += dialog.h \ 22 | serverthread.h \ 23 | server.h \ 24 | mysocket.h 25 | 26 | FORMS += dialog.ui 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QtMultiThreadTcpServer 2 | A multi-thread tcp server base on Qt 3 | -------------------------------------------------------------------------------- /dialog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "server.h" 4 | #include "dialog.h" 5 | #include "ui_dialog.h" 6 | 7 | Dialog::Dialog(QWidget *parent) : 8 | QDialog(parent), 9 | ui(new Ui::Dialog), 10 | m_timer(new QTimer(this)), 11 | m_server(new Server(this)), 12 | m_count(0) 13 | { 14 | ui->setupUi(this); 15 | 16 | setWindowFlags(this->windowFlags() | Qt::WindowMinMaxButtonsHint); 17 | 18 | ui->btnStopLoop->setDisabled(true); 19 | ui->labelNum->setText(QString("%1").arg(m_count)); 20 | 21 | m_server = new Server(this); 22 | m_server->listen(QHostAddress::Any, 8712); 23 | 24 | connect(ui->btnSend, SIGNAL(clicked()), this, SLOT(sendDataSlot())); 25 | connect(ui->btnClear, SIGNAL(clicked()), this, SLOT(clearData())); 26 | connect(m_timer, SIGNAL(timeout()), this, SLOT(startLoopSend())); 27 | connect(ui->btnStopLoop, SIGNAL(clicked(bool)), this, SLOT(stopLoopSend())); 28 | } 29 | 30 | Dialog::~Dialog() 31 | { 32 | delete ui; 33 | } 34 | 35 | void Dialog::showConnection(int sockDesc) 36 | { 37 | m_count++; 38 | 39 | /* add socket object that join in */ 40 | ui->comboBoxObj->addItem(QString("%1").arg(sockDesc), sockDesc); 41 | 42 | /* change connect number while connection is connecting */ 43 | ui->labelNum->setText(QString("%1").arg(m_count)); 44 | } 45 | 46 | void Dialog::showDisconnection(int sockDesc) 47 | { 48 | m_count--; 49 | 50 | /* refresh combobox */ 51 | ui->comboBoxObj->clear(); 52 | int index = ui->comboBoxObj->findData(sockDesc); 53 | 54 | ui->comboBoxObj->removeItem(index); 55 | 56 | /* change connect number while connection is disconnecting */ 57 | ui->labelNum->setText(QString("%1").arg(m_count)); 58 | } 59 | 60 | void Dialog::sendHexData(void) 61 | { 62 | QString allData = ui->lineEditMsg->text(); 63 | QByteArray data; 64 | 65 | QStringList list = allData.split(" "); 66 | for (const QString &hex : list) { 67 | data.append(static_cast(hex.toInt(Q_NULLPTR, 16))); 68 | } 69 | 70 | emit sendData(ui->comboBoxObj->currentText().toInt(), data); 71 | } 72 | 73 | void Dialog::sendDataSlot(void) 74 | { 75 | /* if send message is null return */ 76 | if (ui->lineEditMsg->text().isEmpty()) { 77 | QMessageBox::information(Q_NULLPTR, QString("注意"), QString("发送内容不能为空!"), QMessageBox::Yes); 78 | return ; 79 | } 80 | 81 | if (ui->checkBoxLoop->isChecked()) { 82 | int time_period = ui->lineEditLoopTime->text().toInt(); 83 | 84 | m_timer->setInterval(time_period); 85 | m_timer->start(); 86 | 87 | ui->btnSend->setDisabled(true); 88 | ui->btnStopLoop->setDisabled(false); 89 | return; 90 | } 91 | 92 | /* whether send hex data */ 93 | if (ui->checkBoxHex->isChecked()) { 94 | sendHexData(); 95 | } else { 96 | /* send original data */ 97 | emit sendData(ui->comboBoxObj->currentText().toInt(), ui->lineEditMsg->text().toLocal8Bit()); 98 | } 99 | 100 | ui->lineEditMsg->setText(""); 101 | } 102 | 103 | void Dialog::recvData(const QString &ip, const QByteArray &data) 104 | { 105 | QString msg; 106 | 107 | /* add ip address string to displaying string */ 108 | if (!ui->checkBoxHideIP->isChecked()) { 109 | msg += ip + QString(": "); 110 | } 111 | 112 | /* choose data format to display */ 113 | if (ui->checkBoxHex->isChecked()) { 114 | QString dataString; 115 | for (int i = 0; i < data.size(); i++) { 116 | dataString += QString("0x%1 ").arg(static_cast(data.at(i)), 2, 16, QChar('0')); 117 | } 118 | 119 | msg += dataString + "\n"; 120 | } else { 121 | msg += QString::fromLocal8Bit(data) + "\n"; 122 | } 123 | 124 | /* send back data */ 125 | if (ui->checkBoxCycle->isChecked()) { 126 | emit sendData(ui->comboBoxObj->currentText().toInt(), data); 127 | } 128 | 129 | ui->textBrowser->append(msg); 130 | } 131 | 132 | void Dialog::clearData(void) 133 | { 134 | ui->textBrowser->clear(); 135 | } 136 | 137 | void Dialog::startLoopSend(void) 138 | { 139 | if (ui->checkBoxHex->isChecked()) { 140 | sendHexData(); 141 | } else { 142 | emit sendData(ui->comboBoxObj->currentText().toInt(), ui->lineEditMsg->text().toLocal8Bit()); 143 | } 144 | } 145 | 146 | void Dialog::stopLoopSend(void) 147 | { 148 | m_timer->stop(); 149 | ui->btnSend->setDisabled(false); 150 | ui->btnStopLoop->setDisabled(true); 151 | } 152 | -------------------------------------------------------------------------------- /dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef DIALOG_H 2 | #define DIALOG_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class Dialog; 9 | } 10 | 11 | class Server; 12 | 13 | class Dialog : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit Dialog(QWidget *parent = Q_NULLPTR); 19 | ~Dialog(); 20 | 21 | signals: 22 | void sendData(int id, const QByteArray &data); 23 | 24 | public slots: 25 | void recvData(const QString &ip, const QByteArray &data); 26 | 27 | private slots: 28 | void showConnection(int sockDesc); 29 | void showDisconnection(int sockDesc); 30 | void sendHexData(void); 31 | void sendDataSlot(void); 32 | void clearData(void); 33 | void startLoopSend(void); 34 | void stopLoopSend(void); 35 | 36 | private: 37 | Ui::Dialog *ui; 38 | friend class Server; 39 | 40 | QTimer *m_timer; 41 | Server *m_server; 42 | 43 | int m_count; 44 | }; 45 | 46 | #endif // DIALOG_H 47 | -------------------------------------------------------------------------------- /dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog 4 | 5 | 6 | Qt::NonModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 736 13 | 617 14 | 15 | 16 | 17 | TCP服务器 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 发送 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 发送对象 : 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | HEX收发 55 | 56 | 57 | 58 | 59 | 60 | 61 | 不显示客户端地址 62 | 63 | 64 | 65 | 66 | 67 | 68 | 收发循环 69 | 70 | 71 | 72 | 73 | 74 | 75 | Qt::Horizontal 76 | 77 | 78 | 79 | 40 80 | 20 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 清空接收 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 当前连接数: 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Qt::Horizontal 114 | 115 | 116 | 117 | 40 118 | 20 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 重复发送 127 | 128 | 129 | 130 | 131 | 132 | 133 | 时间间隔: 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | ms 144 | 145 | 146 | 147 | 148 | 149 | 150 | 停止 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "dialog.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | 8 | Dialog w; 9 | w.show(); 10 | 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /mysocket.cpp: -------------------------------------------------------------------------------- 1 | #include "mysocket.h" 2 | 3 | MySocket::MySocket(int sockDesc, QObject *parent) : 4 | QTcpSocket(parent), 5 | m_sockDesc(sockDesc) 6 | { 7 | connect(this, SIGNAL(readyRead()), this, SLOT(recvData())); 8 | } 9 | 10 | MySocket::~MySocket() 11 | { 12 | 13 | } 14 | 15 | void MySocket::sendData(int id, const QByteArray &data) 16 | { 17 | if (id == m_sockDesc && !data.isEmpty()) { 18 | this->write(data); 19 | } 20 | } 21 | 22 | void MySocket::recvData(void) 23 | { 24 | QString ip = peerAddress().toString().remove(0, 7); 25 | QByteArray data = readAll(); 26 | 27 | emit dataReady(ip, data); 28 | } 29 | -------------------------------------------------------------------------------- /mysocket.h: -------------------------------------------------------------------------------- 1 | #ifndef MYSOCKET_H 2 | #define MYSOCKET_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class MySocket : public QTcpSocket 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit MySocket(int sockDesc, QObject *parent = Q_NULLPTR); 14 | ~MySocket(); 15 | 16 | signals: 17 | void dataReady(const QString &ip, const QByteArray &data); 18 | 19 | public slots: 20 | void recvData(void); 21 | void sendData(int id, const QByteArray &data); 22 | 23 | private: 24 | int m_sockDesc; 25 | }; 26 | 27 | #endif // MYSOCKET_H 28 | -------------------------------------------------------------------------------- /server.cpp: -------------------------------------------------------------------------------- 1 | #include "dialog.h" 2 | #include "server.h" 3 | 4 | Server::Server(QObject *parent) : 5 | QTcpServer(parent) 6 | { 7 | /* get current dialog object */ 8 | m_dialog = dynamic_cast(parent); 9 | } 10 | 11 | Server::~Server() 12 | { 13 | 14 | } 15 | 16 | void Server::incomingConnection(int sockDesc) 17 | { 18 | m_socketList.append(sockDesc); 19 | 20 | serverThread *thread = new serverThread(sockDesc); 21 | 22 | m_dialog->showConnection(sockDesc); 23 | 24 | connect(thread, SIGNAL(disconnectTCP(int)), this, SLOT(clientDisconnected(int))); 25 | connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 26 | 27 | connect(thread, SIGNAL(dataReady(const QString&, const QByteArray&)), 28 | m_dialog, SLOT(recvData(const QString&, const QByteArray&))); 29 | 30 | connect(m_dialog, SIGNAL(sendData(int, const QByteArray&)), 31 | thread, SLOT(sendDataSlot(int, const QByteArray&))); 32 | 33 | thread->start(); 34 | } 35 | 36 | void Server::clientDisconnected(int sockDesc) 37 | { 38 | m_dialog->showDisconnection(sockDesc); 39 | } 40 | -------------------------------------------------------------------------------- /server.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_H 2 | #define SERVER_H 3 | 4 | #include 5 | 6 | #include "serverthread.h" 7 | 8 | class Dialog; 9 | 10 | class Server : public QTcpServer 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit Server(QObject *parent = Q_NULLPTR); 15 | ~Server(); 16 | 17 | private: 18 | void incomingConnection(int sockDesc); 19 | 20 | private slots: 21 | void clientDisconnected(int sockDesc); 22 | 23 | private: 24 | Dialog *m_dialog; 25 | 26 | QList m_socketList; 27 | }; 28 | 29 | #endif // SERVER_H 30 | -------------------------------------------------------------------------------- /serverthread.cpp: -------------------------------------------------------------------------------- 1 | #include "serverthread.h" 2 | 3 | serverThread::serverThread(int sockDesc, QObject *parent) : 4 | QThread(parent), 5 | m_sockDesc(sockDesc) 6 | { 7 | 8 | } 9 | 10 | serverThread::~serverThread() 11 | { 12 | m_socket->close(); 13 | } 14 | 15 | void serverThread::run(void) 16 | { 17 | m_socket = new MySocket(m_sockDesc); 18 | 19 | if (!m_socket->setSocketDescriptor(m_sockDesc)) { 20 | return ; 21 | } 22 | 23 | connect(m_socket, &MySocket::disconnected, this, &serverThread::disconnectToHost); 24 | connect(m_socket, SIGNAL(dataReady(const QString&, const QByteArray&)), 25 | this, SLOT(recvDataSlot(const QString&, const QByteArray&))); 26 | connect(this, SIGNAL(sendData(int, const QByteArray&)), 27 | m_socket, SLOT(sendData(int, const QByteArray&))); 28 | 29 | this->exec(); 30 | } 31 | 32 | void serverThread::sendDataSlot(int sockDesc, const QByteArray &data) 33 | { 34 | if (data.isEmpty()) { 35 | return ; 36 | } 37 | 38 | emit sendData(sockDesc, data); 39 | } 40 | 41 | void serverThread::recvDataSlot(const QString &ip, const QByteArray &data) 42 | { 43 | emit dataReady(ip, data); 44 | } 45 | 46 | void serverThread::disconnectToHost(void) 47 | { 48 | emit disconnectTCP(m_sockDesc); 49 | m_socket->disconnectFromHost(); 50 | this->quit(); 51 | } 52 | -------------------------------------------------------------------------------- /serverthread.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVERTHREAD_H 2 | #define SERVERTHREAD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "mysocket.h" 10 | 11 | class Socket; 12 | 13 | class serverThread : public QThread 14 | { 15 | Q_OBJECT 16 | public: 17 | serverThread(int sockDesc, QObject *parent = Q_NULLPTR); 18 | ~serverThread(); 19 | 20 | private: 21 | void run(void); 22 | 23 | public slots: 24 | void sendDataSlot(int sockDesc, const QByteArray &data); 25 | 26 | signals: 27 | void dataReady(const QString &ip, const QByteArray &data); 28 | void sendData(int sockDesc, const QByteArray &data); 29 | void disconnectTCP(int sockDesc); 30 | 31 | private slots: 32 | void recvDataSlot(const QString &ip, const QByteArray &data); 33 | void disconnectToHost(void); 34 | 35 | private: 36 | MySocket *m_socket; 37 | 38 | int m_sockDesc; 39 | }; 40 | 41 | #endif // SERVERTHREAD_H 42 | --------------------------------------------------------------------------------