Qt-tcp通信
1 简介
参考视频:https://www.bilibili.com/video/BV1XW411x7NU?p=56
说明:本文介绍Qt下实现tcp客户端和服务器通信的过程。
Linux下tcp客户端和服务器通信模型可参考我的另一篇博客:https://www.cnblogs.com/mrlayfolk/p/11968446.html。Qt下tcp通信的原理是一样的。
Qt的TCP通信模型如下:
(1)TCP服务器端
1)创建服务器套接字,使用QTcpServer()类;
2)将套接字设置为监听模式;
3)等待客户端连接请求,客户端连接上时会触发newConnection信号,可调用nextPendingConnection函数获取客户端的Socket信息;
4)和客户端进行通信,发送数据可使用write()函数,接收数据可使用read()或readAll函数()。
(2)TCP客户端
1)创建套接字;
2)连接服务器,使用connectToHost()函数;
3)和服务器进行通信,发送数据可使用write()函数,接收数据可使用read()或readAll函数()。
2 测试说明
功能说明:分别创建两个窗口,一个用作TCP服务器端,一个用作TCP客户端,双方进行通信。窗口如下:
服务器窗口: 客户端窗口:
下面分别说明代码实现的步骤:
(1)服务器端
首先创建两个套接字指针。tcpserver用作服务器套接字,tcpsocket用作和客户端通信的通信套接字。
- 1 QTcpServer *tcpserver = NULL; //监听套接字
- 2 QTcpSocket *tcpsocket = NULL; //通信套接字
然后,创建套接字并启动监听。
- 1 //监听套接字,指定父对象,自动回收空间
- 2 tcpserver = new QTcpServer(this);
- 3 //启动监听
- 4 tcpserver->listen(QHostAddress::Any, 8888);
捕捉newConnect信号与槽函数,等待客户端连接:
- 1 //等待连接
- 2 connect(tcpserver, &QTcpServer::newConnection,
- 3 [=]() {
- 4 //取出建立好连接的套接字
- 5 tcpsocket = tcpserver->nextPendingConnection();
- 6 //获取对方的ip的端口
- 7 QString ip = tcpsocket->peerAddress().toString();
- 8 qint16 port = tcpsocket->peerPort();
- 9 QString tmp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
- 10 //在当前对话框显示谁和我连接了
- 11 ui->textEdit_recv->setText(tmp);
- 12 }
- 13 );
发送数据:
- 1 //获取编辑区内容
- 2 QString str = ui->textEdit_send->toPlainText();
- 3 //给对方发送数据
- 4 //QString -> char*
- 5 tcpsocket->write(str.toUtf8().data());
接收数据:
- 1 //接收数据
- 2 connect(tcpsocket, &QTcpSocket::readyRead,
- 3 [=](){
- 4 //从通信套接字中取出内容
- 5 QByteArray array = tcpsocket->readAll();
- 6 ui->textEdit_recv->append(array);
- 7 }
- 8 );
关闭连接:
- 1 //主动和客户端断开连接
- 2 tcpsocket->disconnectFromHost();
- 3 tcpsocket->close();
- 4 tcpsocket = NULL;
(2)客户端
客户端只需要创建一个套接字,用于和服务器建立连接并通信:
- 1 QTcpSocket *tcpsocket = NULL; //通信套接字
- 2 //分配空间,指定父对象
- 3 tcpsocket = new QTcpSocket(this);
和服务器端建立连接:
- 1 //获取服务器ip和端口
- 2 QString ip = ui->lineEdit_ip->text();
- 3 qint16 port = ui->lineEdit_port->text().toInt();
- 4 //主动和服务器建立连接
- 5 tcpsocket->connectToHost(QHostAddress(ip), port);
发送数据:
- 1 //获取编辑框内容
- 2 QString str = ui->textEdit_send->toPlainText();
- 3 //发送数据
- 4 tcpsocket->write(str.toUtf8().data());
接收数据:
- 1 connect(tcpsocket, &QTcpSocket::readyRead,
- 2 [=](){
- 3 //获取对方发送的内容
- 4 QByteArray array = tcpsocket->readAll();
- 5 //追加到编辑区中
- 6 ui->textEdit_recv->append(array);
- 7 }
- 8 );
断开连接:
- 1 //主动和对方断开连接
- 2 tcpsocket->disconnectFromHost();
- 3 tcpsocket->close();
(3)完整的工程代码:
工程所包含的文件有,serverwidget.cpp和serverwidget.h是服务器端的代码,clientwidget.cpp和clientwidget.h是客户端代码。
serverwidget.cpp代码:
- 1 #include "serverwidget.h"
- 2 #include "ui_serverwidget.h"
- 3
- 4 ServerWidget::ServerWidget(QWidget *parent) :
- 5 QWidget(parent),
- 6 ui(new Ui::ServerWidget)
- 7 {
- 8 ui->setupUi(this);
- 9 setWindowTitle("服务器: 8888");
- 10
- 11 //监听套接字,指定父对象,自动回收空间
- 12 tcpserver = new QTcpServer(this);
- 13 //启动监听
- 14 tcpserver->listen(QHostAddress::Any, 8888);
- 15 //等待连接
- 16 connect(tcpserver, &QTcpServer::newConnection,
- 17 [=]() {
- 18 //取出建立好连接的套接字
- 19 tcpsocket = tcpserver->nextPendingConnection();
- 20 //获取对方的ip的端口
- 21 QString ip = tcpsocket->peerAddress().toString();
- 22 qint16 port = tcpsocket->peerPort();
- 23 QString tmp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
- 24 //在当前对话框显示谁和我连接了
- 25 ui->textEdit_recv->setText(tmp);
- 26
- 27 //接收数据
- 28 connect(tcpsocket, &QTcpSocket::readyRead,
- 29 [=](){
- 30 //从通信套接字中取出内容
- 31 QByteArray array = tcpsocket->readAll();
- 32 ui->textEdit_recv->append(array);
- 33 }
- 34 );
- 35 }
- 36 );
- 37 }
- 38
- 39 ServerWidget::~ServerWidget()
- 40 {
- 41 delete ui;
- 42 }
- 43
- 44
- 45 void ServerWidget::on_pushButton_close_clicked()
- 46 {
- 47 if (NULL == tcpsocket) {
- 48 return;
- 49 }
- 50 //主动和客户端断开连接
- 51 tcpsocket->disconnectFromHost();
- 52 tcpsocket->close();
- 53 tcpsocket = NULL;
- 54 }
- 55
- 56 void ServerWidget::on_pushButton_send_clicked()
- 57 {
- 58 if (NULL == tcpsocket) {
- 59 return;
- 60 }
- 61 //获取编辑区内容
- 62 QString str = ui->textEdit_send->toPlainText();
- 63 //给对方发送数据
- 64 //QString -> char*
- 65 tcpsocket->write(str.toUtf8().data());
- 66 }
View Code
serverwidget.h代码:
- 1 #ifndef SERVERWIDGET_H
- 2 #define SERVERWIDGET_H
- 3
- 4 #include <QWidget>
- 5 #include <QTcpServer> //监听套接字
- 6 #include <QTcpSocket> //通信套接字
- 7
- 8 namespace Ui {
- 9 class ServerWidget;
- 10 }
- 11
- 12 class ServerWidget : public QWidget
- 13 {
- 14 Q_OBJECT
- 15
- 16 public:
- 17 explicit ServerWidget(QWidget *parent = 0);
- 18 ~ServerWidget();
- 19
- 20 private slots:
- 21 void on_pushButton_send_clicked();
- 22
- 23 void on_pushButton_close_clicked();
- 24
- 25 private:
- 26 Ui::ServerWidget *ui;
- 27 QTcpServer *tcpserver = NULL; //监听套接字
- 28 QTcpSocket *tcpsocket = NULL; //通信套接字
- 29 };
- 30
- 31 #endif // SERVERWIDGET_H
View Code
clientwidget.cpp代码:
- 1 #include "clientwidget.h"
- 2 #include "ui_clientwidget.h"
- 3 #include <QHostAddress>
- 4
- 5 clientwidget::clientwidget(QWidget *parent) :
- 6 QWidget(parent),
- 7 ui(new Ui::clientwidget)
- 8 {
- 9 ui->setupUi(this);
- 10 setWindowTitle("客户端");
- 11 //分配空间,指定父对象
- 12 tcpsocket = new QTcpSocket(this);
- 13 //建立连接
- 14 connect(tcpsocket, &QTcpSocket::connected,
- 15 [=]() {
- 16 ui->textEdit_recv->setText("成功和服务器建立了连接");
- 17 }
- 18 );
- 19 //接收数据
- 20 connect(tcpsocket, &QTcpSocket::readyRead,
- 21 [=](){
- 22 //获取对方发送的内容
- 23 QByteArray array = tcpsocket->readAll();
- 24 //追加到编辑区中
- 25 ui->textEdit_recv->append(array);
- 26 }
- 27 );
- 28 //断开连接
- 29 connect(tcpsocket, &QTcpSocket::disconnected,
- 30 [=](){
- 31 ui->textEdit_recv->append("和服务器断开了连接");
- 32 }
- 33 );
- 34 }
- 35
- 36 clientwidget::~clientwidget()
- 37 {
- 38 delete ui;
- 39 }
- 40
- 41 void clientwidget::on_pushButton_send_clicked()
- 42 {
- 43 //获取编辑框内容
- 44 QString str = ui->textEdit_send->toPlainText();
- 45 //发送数据
- 46 tcpsocket->write(str.toUtf8().data());
- 47 }
- 48
- 49 void clientwidget::on_pushButton_close_clicked()
- 50 {
- 51 //主动和对方断开连接
- 52 tcpsocket->disconnectFromHost();
- 53 tcpsocket->close();
- 54 }
- 55
- 56 void clientwidget::on_pushButton_connect_clicked()
- 57 {
- 58 //获取服务器ip和端口
- 59 QString ip = ui->lineEdit_ip->text();
- 60 qint16 port = ui->lineEdit_port->text().toInt();
- 61 //主动和服务器建立连接
- 62 tcpsocket->connectToHost(QHostAddress(ip), port);
- 63 }
View Code
clientwidget.h代码:
- 1 #ifndef CLIENTWIDGET_H
- 2 #define CLIENTWIDGET_H
- 3
- 4 #include <QWidget>
- 5 #include <QTcpSocket>
- 6
- 7 namespace Ui {
- 8 class clientwidget;
- 9 }
- 10
- 11 class clientwidget : public QWidget
- 12 {
- 13 Q_OBJECT
- 14
- 15 public:
- 16 explicit clientwidget(QWidget *parent = 0);
- 17 ~clientwidget();
- 18
- 19 private slots:
- 20 void on_pushButton_send_clicked();
- 21
- 22 void on_pushButton_close_clicked();
- 23
- 24 void on_pushButton_connect_clicked();
- 25
- 26 private:
- 27 Ui::clientwidget *ui;
- 28 QTcpSocket *tcpsocket = NULL;
- 29 };
- 30
- 31 #endif // CLIENTWIDGET_H
View Code
main.cpp代码,启动两个窗口:
- 1 #include "serverwidget.h"
- 2 #include <QApplication>
- 3 #include "clientwidget.h"
- 4
- 5 int main(int argc, char *argv[])
- 6 {
- 7 QApplication a(argc, argv);
- 8 ServerWidget w;
- 9 clientwidget w2;
- 10 w.show();
- 11 w2.show();
- 12
- 13 return a.exec();
- 14 }
View Code
运行进行测试: