├── README.md ├── Server ├── inputhandle.h ├── Server.pro ├── main.cpp ├── network.h ├── handle.h ├── inputhandle.cpp ├── handle.cpp └── network.cpp └── Client ├── Client.pro ├── main.cpp ├── inputhandle.h ├── network.h ├── network.cpp └── inputhandle.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Qt5_TCPSocket 2 | Basic TCP server-client communcation model based on QTcpServer & QTcpSocket 3 | -------------------------------------------------------------------------------- /Server/inputhandle.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUTHANDLE_H 2 | #define INPUTHANDLE_H 3 | 4 | #include 5 | #include "network.h" 6 | 7 | class InputHandle : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit InputHandle(Network *n, QObject *parent = 0); 12 | 13 | signals: 14 | 15 | public slots: 16 | void start(void); 17 | 18 | private: 19 | QFile *fin, *fout; 20 | QTextStream sin, sout; 21 | Network *network; 22 | }; 23 | 24 | #endif // INPUTHANDLE_H 25 | -------------------------------------------------------------------------------- /Client/Client.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2014-09-02T10:45:41 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core network 8 | 9 | QT -= gui 10 | 11 | TARGET = Client 12 | CONFIG += console 13 | CONFIG -= app_bundle 14 | 15 | TEMPLATE = app 16 | 17 | 18 | SOURCES += main.cpp \ 19 | network.cpp \ 20 | inputhandle.cpp 21 | 22 | HEADERS += \ 23 | network.h \ 24 | inputhandle.h 25 | -------------------------------------------------------------------------------- /Server/Server.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2014-09-02T10:46:03 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core network 8 | 9 | QT -= gui 10 | 11 | TARGET = Server 12 | CONFIG += console 13 | CONFIG -= app_bundle 14 | 15 | TEMPLATE = app 16 | 17 | 18 | SOURCES += main.cpp \ 19 | network.cpp \ 20 | inputhandle.cpp \ 21 | handle.cpp 22 | 23 | HEADERS += \ 24 | network.h \ 25 | inputhandle.h \ 26 | handle.h 27 | -------------------------------------------------------------------------------- /Client/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "network.h" 4 | #include "inputhandle.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QCoreApplication a(argc, argv); 9 | Network n; 10 | QThread inputHandleThread; 11 | InputHandle ih(&n); 12 | ih.moveToThread(&inputHandleThread); 13 | QObject::connect(&inputHandleThread, SIGNAL(started()), &ih, SLOT(start())); 14 | inputHandleThread.start(); 15 | 16 | int ret = a.exec(); 17 | inputHandleThread.quit(); 18 | inputHandleThread.wait(); 19 | return ret; 20 | } 21 | -------------------------------------------------------------------------------- /Client/inputhandle.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUTHANDLE_H 2 | #define INPUTHANDLE_H 3 | 4 | #include 5 | #include "network.h" 6 | 7 | class InputHandle : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit InputHandle(Network *n, QObject *parent = 0); 12 | 13 | signals: 14 | void connectTo(QString ip, QString port); 15 | void disconnect(); 16 | void send(QString string); 17 | 18 | public slots: 19 | void start(void); 20 | 21 | private: 22 | QFile *fin, *fout; 23 | QTextStream sin, sout; 24 | Network *network; 25 | }; 26 | 27 | #endif // INPUTHANDLE_H 28 | -------------------------------------------------------------------------------- /Server/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "network.h" 4 | #include "inputhandle.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QCoreApplication a(argc, argv); 9 | 10 | Network n; 11 | 12 | QThread inputHandleThread; 13 | InputHandle ih(&n); 14 | ih.moveToThread(&inputHandleThread); 15 | QObject::connect(&inputHandleThread, SIGNAL(started()), &ih, SLOT(start())); 16 | inputHandleThread.start(); 17 | 18 | int ret = a.exec(); 19 | inputHandleThread.quit(); 20 | inputHandleThread.wait(); 21 | 22 | return ret; 23 | } 24 | -------------------------------------------------------------------------------- /Server/network.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORK_H 2 | #define NETWORK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Network : public QObject 10 | { 11 | Q_OBJECT 12 | friend class InputHandle; 13 | public: 14 | explicit Network(QObject *parent = 0); 15 | ~Network(void); 16 | 17 | signals: 18 | 19 | public slots: 20 | 21 | private slots: 22 | void newConnection(void); 23 | void join(QThread *thread); 24 | 25 | private: 26 | QTcpServer *server; 27 | QList threadPool; 28 | }; 29 | 30 | #endif // NETWORK_H 31 | -------------------------------------------------------------------------------- /Server/handle.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLE_H 2 | #define HANDLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Handle : public QObject 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit Handle(QTcpSocket *s, QObject *parent = 0) : QObject(parent), socket(s) {} 13 | 14 | public slots: 15 | void start(); 16 | 17 | protected: 18 | void timerEvent(QTimerEvent *); 19 | 20 | signals: 21 | void JSONReceived(QJsonDocument doc); 22 | void finished(QThread *); 23 | 24 | private slots: 25 | void disconnected(); 26 | void read(); 27 | 28 | private: 29 | int timerID; 30 | qint64 bytesAvailable; 31 | QTcpSocket *socket; 32 | }; 33 | 34 | #endif // HANDLE_H 35 | -------------------------------------------------------------------------------- /Client/network.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORK_H 2 | #define NETWORK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class Network : public QObject 11 | { 12 | Q_OBJECT 13 | friend class InputHandle; 14 | public: 15 | explicit Network(QObject *parent = 0); 16 | ~Network(void); 17 | 18 | signals: 19 | 20 | public slots: 21 | void connectTo(QString ip, QString port); 22 | void disconnect(); 23 | void send(QString string); 24 | void send(QJsonDocument doc); 25 | 26 | private slots: 27 | void connected(void); 28 | void disconnected(void); 29 | 30 | private: 31 | QTcpSocket *socket; 32 | }; 33 | 34 | #endif // NETWORK_H 35 | -------------------------------------------------------------------------------- /Server/inputhandle.cpp: -------------------------------------------------------------------------------- 1 | #include "inputhandle.h" 2 | #include 3 | #include 4 | 5 | InputHandle::InputHandle(Network *n, QObject *parent) : 6 | QObject(parent), network(n) 7 | { 8 | fin = new QFile(this); 9 | fin->open(stdin, QIODevice::ReadOnly); 10 | sin.setDevice(fin); 11 | fout = new QFile(this); 12 | fout->open(stdout, QIODevice::WriteOnly); 13 | sout.setDevice(fout); 14 | } 15 | 16 | void InputHandle::start(void) 17 | { 18 | loop: 19 | sout.flush(); 20 | QString input(sin.readLine()); 21 | if (input.isNull()) 22 | goto loop; 23 | if (input == "stop") { 24 | qApp->quit(); 25 | return; 26 | } else if (input == "state") { 27 | if (network->server->isListening()) 28 | sout << "[INFO] Server listening\n"; 29 | else 30 | sout << "[INFO] Server not listening\n"; 31 | } 32 | goto loop; 33 | } 34 | -------------------------------------------------------------------------------- /Client/network.cpp: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include 3 | #include 4 | #include 5 | 6 | Network::Network(QObject *parent) : 7 | QObject(parent) 8 | { 9 | socket = new QTcpSocket; 10 | connect(socket, SIGNAL(connected()), this, SLOT(connected())); 11 | connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); 12 | qDebug() << "[INFO] Client started"; 13 | } 14 | 15 | Network::~Network(void) 16 | { 17 | qDebug() << "[INFO] Stopping the client..."; 18 | } 19 | 20 | void Network::connected(void) 21 | { 22 | qDebug() << "[INFO] Connected"; 23 | } 24 | 25 | void Network::disconnected(void) 26 | { 27 | qDebug() << "[INFO] Disonnected"; 28 | } 29 | 30 | void Network::connectTo(QString ip, QString port) 31 | { 32 | //socket->connectToHost(QHostAddress(ip), port.toInt()); 33 | socket->connectToHost(ip, port.toInt()); 34 | } 35 | 36 | void Network::disconnect() 37 | { 38 | socket->disconnectFromHost(); 39 | } 40 | 41 | void Network::send(QString string) 42 | { 43 | QJsonDocument doc; 44 | QJsonArray array; 45 | array.append(QJsonValue(string)); 46 | doc.setArray(array); 47 | send(doc); 48 | } 49 | 50 | void Network::send(QJsonDocument doc) 51 | { 52 | socket->write(doc.toJson()); 53 | } 54 | -------------------------------------------------------------------------------- /Server/handle.cpp: -------------------------------------------------------------------------------- 1 | #include "handle.h" 2 | #include 3 | #include 4 | 5 | void Handle::start() 6 | { 7 | bytesAvailable = 0; 8 | timerID = startTimer(10); 9 | connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); 10 | connect(socket, SIGNAL(readyRead()), this, SLOT(read())); 11 | qDebug() << "[HANDLE]" << QThread::currentThread() << "New connection"; 12 | } 13 | 14 | void Handle::timerEvent(QTimerEvent *) 15 | { 16 | qint64 bytes = bytesAvailable; 17 | bytesAvailable = socket->bytesAvailable(); 18 | //qDebug() << __func__ << timerID << bytes << bytesAvailable; 19 | if (bytesAvailable != bytes) 20 | return; 21 | killTimer(timerID); 22 | timerID = 0; 23 | if (bytesAvailable == 0) 24 | return; 25 | bytesAvailable = 0; 26 | 27 | QByteArray data = socket->readAll(); 28 | QJsonDocument doc = QJsonDocument::fromJson(data); 29 | if (doc.isNull()) { 30 | qDebug() << "[HANDLE]" << QThread::currentThread() << "Invalid JSON received!" << data; 31 | return; 32 | } 33 | qDebug() << "[DEBUG]" << QThread::currentThread() << "JSON received:" << doc; 34 | emit JSONReceived(doc); 35 | } 36 | 37 | void Handle::disconnected() 38 | { 39 | qDebug() << "[HANDLE]" << QThread::currentThread() << "Disconnected"; 40 | emit finished(QThread::currentThread()); 41 | } 42 | 43 | void Handle::read() 44 | { 45 | if (!timerID) 46 | timerID = startTimer(10); 47 | } 48 | -------------------------------------------------------------------------------- /Server/network.cpp: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "handle.h" 3 | #include 4 | #include 5 | #include 6 | 7 | Network::Network(QObject *parent) : 8 | QObject(parent) 9 | { 10 | server = new QTcpServer(this); 11 | if (!server->listen(QHostAddress::Any, 6000)) 12 | qFatal("Cannot listen on port 6000!"); 13 | connect(server, SIGNAL(newConnection()), this, SLOT(newConnection())); 14 | qDebug() << "[INFO] Server started"; 15 | } 16 | 17 | Network::~Network(void) 18 | { 19 | qDebug() << "[INFO] Stopping the server..."; 20 | foreach (QThread *thread, threadPool) { 21 | thread->quit(); 22 | thread->wait(); 23 | qDebug() << "[HANDLE]" << thread << "Deleted"; 24 | delete thread; 25 | } 26 | } 27 | 28 | void Network::newConnection(void) 29 | { 30 | QThread *handleThread = new QThread(this); 31 | threadPool.append(handleThread); 32 | QTcpSocket *socket = server->nextPendingConnection(); 33 | connect(handleThread, SIGNAL(finished()), socket, SLOT(deleteLater())); 34 | Handle *handle = new Handle(socket); 35 | connect(handleThread, SIGNAL(started()), handle, SLOT(start())); 36 | connect(handleThread, SIGNAL(finished()), handle, SLOT(deleteLater())); 37 | connect(handle, SIGNAL(finished(QThread*)), this, SLOT(join(QThread*))); 38 | handle->moveToThread(handleThread); 39 | handleThread->start(); 40 | } 41 | 42 | void Network::join(QThread *thread) 43 | { 44 | thread->quit(); 45 | thread->wait(); 46 | threadPool.removeAll(thread); 47 | qDebug() << "[HANDLE]" << thread << "Deleted"; 48 | delete thread; 49 | } 50 | -------------------------------------------------------------------------------- /Client/inputhandle.cpp: -------------------------------------------------------------------------------- 1 | #include "inputhandle.h" 2 | #include 3 | #include 4 | #include 5 | 6 | InputHandle::InputHandle(Network *n, QObject *parent) : 7 | QObject(parent), network(n) 8 | { 9 | fin = new QFile(this); 10 | fin->open(stdin, QIODevice::ReadOnly); 11 | sin.setDevice(fin); 12 | fout = new QFile(this); 13 | fout->open(stdout, QIODevice::WriteOnly); 14 | sout.setDevice(fout); 15 | connect(this, SIGNAL(connectTo(QString,QString)), network, SLOT(connectTo(QString,QString))); 16 | connect(this, SIGNAL(disconnect()), network, SLOT(disconnect())); 17 | connect(this, SIGNAL(send(QString)), network, SLOT(send(QString))); 18 | } 19 | 20 | void InputHandle::start(void) 21 | { 22 | loop: 23 | sout.flush(); 24 | QStringList input(sin.readLine().split(" ")); 25 | if (input.size() == 0) 26 | return; 27 | QString cmd = input.at(0); 28 | if (cmd == "stop") { 29 | qApp->quit(); 30 | return; 31 | } else if (cmd == "connect") { 32 | if (input.size() != 3) { 33 | sout << "[CMD] You need to specify host address and port!\n"; 34 | goto loop; 35 | } 36 | QString host = input.at(1), port = input.at(2); 37 | if (host.isEmpty()) 38 | sout << "[INFO] You need to specify host address and port!\n"; 39 | else if (network->socket->state() != QTcpSocket::UnconnectedState) 40 | sout << "[INFO] Already connected!\n"; 41 | else 42 | emit connectTo(host, port); 43 | } else if (cmd == "disconnect") { 44 | emit disconnect(); 45 | } else if (cmd == "send") { 46 | if (input.size() != 2) { 47 | sout << "[CMD] You need to specify the data!\n"; 48 | goto loop; 49 | } 50 | if (network->socket->state() != QTcpSocket::ConnectedState) { 51 | sout << "[CMD] Not yet connected!\n"; 52 | goto loop; 53 | } 54 | emit send(input.at(1)); 55 | } else if (cmd == "state") 56 | sout << (network->socket->state()) << '\n'; 57 | goto loop; 58 | } 59 | --------------------------------------------------------------------------------