服务端:(QTcpServer)
①创建QTcpServer对象
②监听list需要的参数是地址和端口号
③当有新的客户端连接成功回发送newConnect信号
④在newConnection信号槽函数中,调用nextPendingConnection函数获取新连接QTcpSocket对象
⑤连接QTcpSocket对象的readRead信号
⑥在readRead信号的槽函数使用read接收数据
⑦调用write成员函数发送数据
客户端:(QTcpSocket)
①创建QTcpSocket对象
②当对象与Server连接成功时会发送connected 信号
③调用成员函数connectToHost连接服务器,需要的参数是地址和端口号
④connected信号的槽函数开启发送数据
⑤使用write发送数据,read接收数据
Qt tcp服务器示例
在这个示例中,我们创建了一个名为TcpServer的类,继承自QTcpServer,重写了incomingConnection()方法来处理新的客户端连接。每个连接都会创建一个ClientHandler对象,ClientHandler继承自QRunnable,处理与客户端的通信。QThreadPool负责管理和调度这些ClientHandler对象。
#include "main.moc"
这一行是在使用Qt的moc(元对象编译器)时生成的一个包含文件。在Qt中,为了实现信号和槽、内省和动态属性等特性,需要用到Qt的元对象系统。moc的作用是在编译时解析含有Q_OBJECT宏的类,为这些类生成一个额外的C++源文件,这个文件包含了元对象信息。在我们的示例中,TcpServer类包含了Q_OBJECT宏,所以需要使用moc处理。通常情况下,moc会生成一个名为“classname.moc”的文件。这个文件会被自动包含到构建过程中,所以我们不需要手动添加它。但在这个示例中,我们把所有代码都放在了一个文件中,所以需要显式地包含这个moc文件。如果你在一个项目中使用多个文件,你可以将类的声明和实现放在不同的文件中,并且不需要显式地包含moc文件,因为构建系统会自动处理它。
需要注意的是,如果你使用了qmake、CMake或者其他支持Qt的构建系统,它们会自动调用moc并处理这些文件,你不需要手动添加
#include "main.moc"
。在这个简化示例中,我们显式地包含了moc文件,但在实际项目中,你通常不需要这么做。
#include <QCoreApplication> #include <QTcpServer> #include <QTcpSocket> #include <QThreadPool> #include <QDebug> #include <QRunnable> class ClientHandler : public QRunnable { public: ClientHandler(qintptr socketDescriptor) : m_socketDescriptor(socketDescriptor) {} void run() override { QTcpSocket socket; if (!socket.setSocketDescriptor(m_socketDescriptor)) { qDebug() << "Failed to set socket descriptor."; return; } while (socket.state() == QAbstractSocket::ConnectedState) { if (socket.waitForReadyRead()) { QByteArray data = socket.readAll(); qDebug() << "Received data:" << data; socket.write(data); } } } private: qintptr m_socketDescriptor; }; class TcpServer : public QTcpServer { Q_OBJECT public: TcpServer(QObject *parent = nullptr) : QTcpServer(parent) {} protected: void incomingConnection(qintptr socketDescriptor) override { qDebug() << "New connection:" << socketDescriptor; auto clientHandler = new ClientHandler(socketDescriptor); QThreadPool::globalInstance()->start(clientHandler); } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); TcpServer server; if (!server.listen(QHostAddress::Any, 12345)) { qDebug() << "Failed to start server:" << server.errorString(); return 1; } qDebug() << "Server started on port" << server.serverPort(); return app.exec(); } #include "main.moc"
Qt tcp客户端示例
以下是一个简单的Qt环境下的TCP客户端示例,展示了如何使用多线程连接两个TCP服务器并进行交互。
在这个示例中,我们创建了一个名为TcpClient的类,继承自QObject。我们还创建了一个名为DataProcessor的类,同样继承自QObject。TcpClient类包含了一个QTcpSocket对象,用于连接服务器和发送/接收数据。当连接建立后,TcpClient会在一个while循环中等待服务器发送数据。每当有数据到达时,TcpClient会发出一个processData()信号,这个信号会被连接到DataProcessor类的processData()槽函数中进行处理。处理完成后,DataProcessor会发出一个sendData()信号,这个信号会被连接到TcpClient的onSendData()槽函数中,将数据发送回服务器。
在main()函数中,我们创建了两个TcpClient对象,并将它们移动到不同的线程中。每个线程都会连接一个不同的服务器,并在连接建立后发送数据。我们还创建了一个DataProcessor对象,并将它移动到另一个线程中。DataProcessor会处理收到的数据并将处理后的数据发送回TcpClient,然后TcpClient将处理后的数据发送回服务器。这个过程中,DataProcessor和TcpClient是在不同的线程中运行的,因此我们使用了信号和槽来实现跨线程通信。
需要注意的是,这个示例中的DataProcessor类只是一个简单的例子,它把收到的数据转换为大写字母并返回。在实际应用中,你可以将DataProcessor替换为一个更复杂的类,用于处理实际的业务逻辑。此外,这个示例中的TcpClient类仅支持单向通信,即只有服务器向客户端发送数据。如果你需要双向通信,你需要修改TcpClient类以便它可以接收来自服务器的数据,并在必要时发送回复。
#include <QCoreApplication> #include <QThread> #include <QTcpSocket> #include <QDebug> #include <QMutex> class DataProcessor : public QObject { Q_OBJECT public slots: QByteArray processData(const QByteArray &data) { qDebug() << "Processing data:" << data; QByteArray processedData = data.toUpper(); return processedData; } }; class TcpClient : public QObject { Q_OBJECT public: TcpClient(const QString &host, int port, QObject *parent = nullptr) : QObject(parent), m_host(host), m_port(port), m_socket(nullptr) {} public slots: void connectToServer() { m_socket = new QTcpSocket(); m_socket->connectToHost(m_host, m_port); if (m_socket->waitForConnected()) { qDebug() << "Connected to server:" << m_host << m_port; sendData("Hello, server!"); while (m_socket->state() == QAbstractSocket::ConnectedState) { if (m_socket->waitForReadyRead()) { QByteArray data = m_socket->readAll(); qDebug() << "Received data:" << data; QByteArray processedData = processData(data); sendData(processedData); } } } else { qDebug() << "Failed to connect to server:" << m_host << m_port; } m_socket->deleteLater(); } signals: QByteArray processData(const QByteArray &data); void sendData(const QByteArray &data); private slots: void onSendData(const QByteArray &data) { if (m_socket && m_socket->state() == QAbstractSocket::ConnectedState) { m_socket->write(data); } } private: QString m_host; int m_port; QTcpSocket *m_socket; }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QThread dataProcessorThread; DataProcessor dataProcessor; dataProcessor.moveToThread(&dataProcessorThread); dataProcessorThread.start(); QThread client1Thread; TcpClient client1("localhost", 12345); client1.moveToThread(&client1Thread); QObject::connect(&client1, &TcpClient::processData, &dataProcessor, &DataProcessor::processData); QObject::connect(&client1, &TcpClient::sendData, &client1, &TcpClient::onSendData); QObject::connect(&client1Thread, &QThread::started, &client1, &TcpClient::connectToServer); client1Thread.start(); QThread client2Thread; TcpClient client2("localhost", 12346); client2.moveToThread(&client2Thread); QObject::connect(&client2, &TcpClient::processData, &dataProcessor, &DataProcessor::processData); QObject::connect(&client2, &TcpClient::sendData, &client2, &TcpClient::onSendData); QObject::connect(&client2Thread, &QThread::started, &client2, &TcpClient::connectToServer); client2Thread.start(); QObject::connect(&app, &QCoreApplication::aboutToQuit, [&](){ client1Thread.quit(); client1Thread.wait(); client2Thread.quit(); client2Thread.wait(); dataProcessorThread.quit(); dataProcessorThread.wait(); }); return app.exec(); } #include "main.moc"