1  簡介

參考視頻: https://www.bilibili.com/video/BV1XW411x7NU?p=56

測試代碼github: https://github.com/zhengcixi/Qt_Demo/tree/master/tcp

說明:本文介紹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

運行進行測試:

相關文章