Qt 實現簡單的TCP通信


這段時間用到了QT的TCP通信,做了初步的學習與嘗試,編寫了一個客戶端和服務器基於窗口通信的小例程。

使用QT的網絡套接字需要.pro文件中加入一句:

QT += network

一、客戶端

1、客戶端的代碼比服務器稍簡單,總的來說,使用QT中的QTcpSocket類與服務器進行通信只需要以下5步:

(1)創建QTcpSocket套接字對象

socket = new QTcpSocket();

(2)使用這個對象連接服務器

socket->connectToHost(IP, port);

(3)使用write函數向服務器發送數據

socket->write(data);

(4)當socket接收緩沖區有新數據到來時,會發出readRead()信號,因此為該信號添加槽函數以讀取數據

1 QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); 2  
3 void MainWindow::socket_Read_Data() 4 { 5  QByteArray buffer; 6     //讀取緩沖區數據
7     buffer = socket->readAll(); 8 }

(5)斷開與服務器的連接(關於close()和disconnectFromHost()的區別,可以按F1看幫助)

socket->disconnectFromHost();

2、以下是客戶端的例程

首先是mainwindow.h文件:

 1 //mainwindow.h
 2 #ifndef MAINWINDOW_H  3 #define MAINWINDOW_H
 4  
 5 #include <QMainWindow>
 6 #include <QTcpSocket>
 7  
 8 namespace Ui {  9 class MainWindow; 10 } 11  
12 class MainWindow : public QMainWindow 13 { 14  Q_OBJECT 15  
16 public: 17     explicit MainWindow(QWidget *parent = 0); 18     ~MainWindow(); 19  
20 private slots: 21  
22     void on_pushButton_Connect_clicked(); 23  
24     void on_pushButton_Send_clicked(); 25  
26     void socket_Read_Data(); 27  
28     void socket_Disconnected(); 29  
30 private: 31     Ui::MainWindow *ui; 32     QTcpSocket *socket; 33 }; 34  
35 #endif // MAINWINDOW_H

然后是mainwindow.cpp文件:

 1 //mainwindow.cpp
 2 #include "mainwindow.h"
 3 #include "ui_mainwindow.h"
 4  
 5 MainWindow::MainWindow(QWidget *parent) :  6  QMainWindow(parent),  7     ui(new Ui::MainWindow)  8 {  9     ui->setupUi(this); 10  
11     socket = new QTcpSocket(); 12  
13     //連接信號槽
14     QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); 15     QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected); 16  
17     ui->pushButton_Send->setEnabled(false); 18     ui->lineEdit_IP->setText("127.0.0.1"); 19     ui->lineEdit_Port->setText("8765"); 20  
21 } 22  
23 MainWindow::~MainWindow() 24 { 25     delete this->socket; 26     delete ui; 27 } 28  
29 void MainWindow::on_pushButton_Connect_clicked() 30 { 31     if(ui->pushButton_Connect->text() == tr("連接")) 32  { 33  QString IP; 34         int port; 35  
36         //獲取IP地址
37         IP = ui->lineEdit_IP->text(); 38         //獲取端口號
39         port = ui->lineEdit_Port->text().toInt(); 40  
41         //取消已有的連接
42         socket->abort(); 43         //連接服務器
44         socket->connectToHost(IP, port); 45  
46         //等待連接成功
47         if(!socket->waitForConnected(30000)) 48  { 49             qDebug() << "Connection failed!"; 50             return; 51  } 52         qDebug() << "Connect successfully!"; 53  
54         //發送按鍵使能
55         ui->pushButton_Send->setEnabled(true); 56         //修改按鍵文字
57         ui->pushButton_Connect->setText("斷開連接"); 58  } 59     else
60  { 61         //斷開連接
62         socket->disconnectFromHost(); 63         //修改按鍵文字
64         ui->pushButton_Connect->setText("連接"); 65         ui->pushButton_Send->setEnabled(false); 66  } 67 } 68  
69 void MainWindow::on_pushButton_Send_clicked() 70 { 71     qDebug() << "Send: " << ui->textEdit_Send->toPlainText(); 72      //獲取文本框內容並以ASCII碼形式發送
73     socket->write(ui->textEdit_Send->toPlainText().toLatin1()); 74     socket->flush(); 75 } 76  
77 void MainWindow::socket_Read_Data() 78 { 79  QByteArray buffer; 80     //讀取緩沖區數據
81     buffer = socket->readAll(); 82     if(!buffer.isEmpty()) 83  { 84         QString str = ui->textEdit_Recv->toPlainText(); 85         str+=tr(buffer); 86         //刷新顯示
87         ui->textEdit_Recv->setText(str); 88  } 89 } 90  
91 void MainWindow::socket_Disconnected() 92 { 93     //發送按鍵失能
94     ui->pushButton_Send->setEnabled(false); 95     //修改按鍵文字
96     ui->pushButton_Connect->setText("連接"); 97     qDebug() << "Disconnected!"; 98 }

最后是ui的設計:

二、服務器

1、服務器除了使用到了QTcpSocket類,還需要用到QTcpSever類。即便如此,也只是比客戶端復雜一點點,用到了6個步驟:

(1)創建QTcpSever對象

server = new QTcpServer();

(2)偵聽一個端口,使得客戶端可以使用這個端口訪問服務器

server->listen(QHostAddress::Any, port);

(3)當服務器被客戶端訪問時,會發出newConnection()信號,因此為該信號添加槽函數,並用一個QTcpSocket對象接受客戶端訪問

1 connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect); 2  
3 void MainWindow::server_New_Connect() 4 { 5     //獲取客戶端連接
6     socket = server->nextPendingConnection(); 7 }

(4)使用socket的write函數向客戶端發送數據

socket->write(data);

(5)當socket接收緩沖區有新數據到來時,會發出readRead()信號,因此為該信號添加槽函數以讀取數據

1 QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); 2  
3 void MainWindow::socket_Read_Data() 4 { 5  QByteArray buffer; 6     //讀取緩沖區數據
7     buffer = socket->readAll(); 8 }

(6)取消偵聽

server->close();

2、以下是服務器的例程

首先是mainwindow.h文件:

 1 //mainwindow.h
 2 #ifndef MAINWINDOW_H  3 #define MAINWINDOW_H
 4  
 5 #include <QMainWindow>
 6 #include <QTcpServer>
 7 #include <QTcpSocket>
 8  
 9 namespace Ui { 10 class MainWindow; 11 } 12  
13 class MainWindow : public QMainWindow 14 { 15  Q_OBJECT 16  
17 public: 18     explicit MainWindow(QWidget *parent = 0); 19     ~MainWindow(); 20  
21 private slots: 22     void on_pushButton_Listen_clicked(); 23  
24     void on_pushButton_Send_clicked(); 25  
26     void server_New_Connect(); 27  
28     void socket_Read_Data(); 29  
30     void socket_Disconnected(); 31  
32 private: 33     Ui::MainWindow *ui; 34     QTcpServer* server; 35     QTcpSocket* socket; 36 }; 37  
38 #endif // MAINWINDOW_H

然后是mainwindow.cpp文件:

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3  
 4 MainWindow::MainWindow(QWidget *parent) :  5  QMainWindow(parent),  6     ui(new Ui::MainWindow)  7 {  8     ui->setupUi(this);  9  
 10     ui->lineEdit_Port->setText("8765");  11     ui->pushButton_Send->setEnabled(false);  12  
 13     server = new QTcpServer();  14  
 15     //連接信號槽
 16     connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect);  17 }  18  
 19 MainWindow::~MainWindow()  20 {  21     server->close();  22     server->deleteLater();  23     delete ui;  24 }  25  
 26 void MainWindow::on_pushButton_Listen_clicked()  27 {  28     if(ui->pushButton_Listen->text() == tr("偵聽"))  29  {  30         //從輸入框獲取端口號
 31         int port = ui->lineEdit_Port->text().toInt();  32  
 33         //監聽指定的端口
 34         if(!server->listen(QHostAddress::Any, port))  35  {  36             //若出錯,則輸出錯誤信息
 37             qDebug()<<server->errorString();  38             return;  39  }  40         //修改按鍵文字
 41         ui->pushButton_Listen->setText("取消偵聽");  42         qDebug()<< "Listen succeessfully!";  43  }  44     else
 45  {  46 /*
 47  //如果正在連接(點擊偵聽后立即取消偵聽,若socket沒有指定對象會有異常,應修正——2017.9.30)  48  if(socket->state() == QAbstractSocket::ConnectedState)  49  {  50  //關閉連接  51  socket->disconnectFromHost();  52  }  53 */
 54         socket->abort();  55         //取消偵聽
 56         server->close();  57         //修改按鍵文字
 58         ui->pushButton_Listen->setText("偵聽");  59         //發送按鍵失能
 60         ui->pushButton_Send->setEnabled(false);  61  }  62  
 63 }  64  
 65 void MainWindow::on_pushButton_Send_clicked()  66 {  67     qDebug() << "Send: " << ui->textEdit_Send->toPlainText();  68     //獲取文本框內容並以ASCII碼形式發送
 69     socket->write(ui->textEdit_Send->toPlainText().toLatin1());  70     socket->flush();  71 }  72  
 73 void MainWindow::server_New_Connect()  74 {  75     //獲取客戶端連接
 76     socket = server->nextPendingConnection();  77     //連接QTcpSocket的信號槽,以讀取新數據
 78     QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);  79     QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);  80     //發送按鍵使能
 81     ui->pushButton_Send->setEnabled(true);  82  
 83     qDebug() << "A Client connect!";  84 }  85  
 86 void MainWindow::socket_Read_Data()  87 {  88  QByteArray buffer;  89     //讀取緩沖區數據
 90     buffer = socket->readAll();  91     if(!buffer.isEmpty())  92  {  93         QString str = ui->textEdit_Recv->toPlainText();  94         str+=tr(buffer);  95         //刷新顯示
 96         ui->textEdit_Recv->setText(str);  97  }  98 }  99  
100 void MainWindow::socket_Disconnected() 101 { 102     //發送按鍵失能
103     ui->pushButton_Send->setEnabled(false); 104     qDebug() << "Disconnected!"; 105 }

最后是ui的設計:

 三、運行結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM