QT之TCP通訊

QT中能夠經過TCP協議讓服務器和客戶端之間行通訊。因此下面我就圍繞服務器和客戶端來寫。服務器

這是咱們寫服務器和客戶端的具體流程:app

A、服務器:      socket

         1.建立QTcpServer對象
         2.啓動服務器(監聽)調用成員方法listen(QHostAddress::Any,端口號)
         3.當有客戶端連接時候會發送newConnection信號,觸發槽函數接受連接(獲得一個與客戶端通訊的套接字QTcpSocket)
         4.QTcpsocket發送數據用成員方法write,
         5.讀數據當客戶端有數據來,QTcpSocket對象就會發送readyRead信號,關聯槽函數讀取數據tcp

B、客戶端  :  編輯器

        1.建立QTcpSocket對象
        2.連接服務器connectToHost(QHostAddress("ip"),端口號)
        3.QTcpsocket發送數據用成員方法write,
        4.讀數據當對方有數據來,QTcpSocket對象就會發送readyRead信號,關聯槽函數讀取數據ide

 

咱們須要調用到的頭文件有兩個函數

#include <QTcpServer>  
#include <QTcpSocket>

咱們先要在工程文件中加入networkui

QT       += core gui network

下面咱們來看看服務器程序步驟:this

一、初始化服務器server對象編碼

mServer = new QTcpServer();

二、啓動監聽服務器

  mServer->listen(QHostAddress::Any,9988);//9988爲端口號

三、當有客戶端連接時候會發送newConnection信號,觸發槽函數接受連接(獲得一個與客戶端通訊的套接字QTcpSocket)

 connect(mServer,SIGNAL(newConnection()),this,SLOT(new_client()));
 mSocket = mServer->nextPendingConnection();//與客戶端通訊的套接字

四、發送數據

 mSocket->write(msg.toUtf8());

五、讀數據當客戶端有數據來,QTcpSocket對象就會發送readyRead信號,關聯槽函數讀取數據

 connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_client_data()));

六、鏈接多個客戶端

 //能夠實現同時讀取多個客戶端發送過來的消息
 QTcpSocket *obj = (QTcpSocket*)sender();

七、檢測掉線

 connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis())); //檢測掉線信號

下面是服務器的實現的具體代碼:

 1 #include "tcpserver.h"
 2 #include "ui_tcpserver.h"
 3 #include <QDebug>
 4 TcpServer::TcpServer(QWidget *parent) :
 5     QMainWindow(parent),
 6     ui(new Ui::TcpServer)
 7 {
 8     ui->setupUi(this);
 9     //初始化服務器server對象
10     mServer = new QTcpServer();
11     //關聯客戶端鏈接信號newConnection
12     connect(mServer,SIGNAL(newConnection()),this,SLOT(new_client())); //鏈接客戶端
13     //啓動服務器監聽
14     mServer->listen(QHostAddress::Any,9988);
15 
16 }
17 
18 TcpServer::~TcpServer()
19 {
20     delete ui;
21 }
22 
23 void TcpServer::new_client()
24 {
25     qDebug()<<"新客戶段鏈接";
26     mSocket = mServer->nextPendingConnection();//與客戶端通訊的套接字
27     //關聯接收客戶端數據信號readyRead信號(客戶端有數據就會發readyRead信號)
28     connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_client_data()));
29     //檢測掉線信號
30     connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));
31 
32 }
33 
34 void TcpServer::read_client_data()
35 {
36     //能夠實現同時讀取多個客戶端發送過來的消息
37     QTcpSocket *obj = (QTcpSocket*)sender();
38     QString msg = obj->readAll();
39     qDebug()<<msg;
40 }
41 
42 void TcpServer::client_dis()
43 {
44      QTcpSocket *obj = (QTcpSocket*)sender();//掉線對象
45      qDebug()<<obj->peerAddress().toString();//打印出掉線對象的ip
46 }

 

說完服務器那咱們繼續來看看客戶端是怎麼實現的:

一、建立QTcpSocket對象

 mSocket = new QTcpSocket();

二、連接服務器connectToHost(QHostAddress("ip"),端口號),鏈接服務器ip和端口號

 mSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt()); //ui->ipEdit->text():ip,ui->portEdit->text().toInt():端口號

三、發送數據

//取發送信息編輯框內容
QString msg = ui->sendEdit->toPlainText();
mSocket->write(msg.toUtf8());//轉編碼

四、檢測連接成功信號關聯槽函數

 connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));

五、檢測掉線信號

 connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));

六、服務器和客戶端關閉均可以使用close

 mSocket->close();

這是客戶端實現的具體代碼

 1 #include "tcpclient.h"
 2 #include "ui_tcpclient.h"
 3 #include <QDebug>
 4 TcpClient::TcpClient(QWidget *parent) :
 5     QMainWindow(parent),
 6     ui(new Ui::TcpClient)
 7 {
 8     ui->setupUi(this);
 9     //初始化套接字對象
10     mSocket = new QTcpSocket();
11     //關聯數據信號
12     connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_data()));
13 
14 }
15 
16 TcpClient::~TcpClient()
17 {
18     delete ui;
19 }
20 
21 void TcpClient::read_data()
22 {
23     QString msg = mSocket->readAll();
24     qDebug()<<msg;
25 }
26 
27 void TcpClient::on_btn_connectServer_clicked()
28 {
29     //檢測連接成功信號關聯槽函數
30     connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));
31     //檢測掉線信號
32     connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));
33     //鏈接服務器,設置ip和端口號
34     mSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt());
35 
36 }
37 
38 void TcpClient::on_btn_send_clicked()
39 {
40     //取發送信息編輯框內容
41     QString msg = ui->sendEdit->toPlainText();
42     mSocket->write(msg.toUtf8());//轉編碼
43 }
44 
45 void TcpClient::connect_suc()
46 {
47     ui->btn_connectServer->setEnabled(false);//若是鏈接成功則鏈接按鈕不能按下
48 }
49 void TcpClient::client_dis()
50 {
51     ui->btn_connectServer->setEnabled(true);//若是鏈接沒有成功則鏈接按鈕還能夠按下
52 }

 

這是服務器和客戶端分開兩個文件夾寫的程序,在這裏我也實現了服務器和客戶端寫在同一個文件中

具體代碼以下:

頭文件:tcpapp.h

 1 #ifndef TCPAPP_H
 2 #define TCPAPP_H
 3 
 4 #include <QMainWindow>
 5 #include <QTcpServer>
 6 #include <QTcpSocket>
 7 #include <QHostAddress>
 8 #include <QFile>
 9 #include <QTimer>
10 #include <QMessageBox>
11 namespace Ui {
12 class TcpApp;
13 }
14 
15 class TcpApp : public QMainWindow
16 {
17     Q_OBJECT
18 
19 public:
20     explicit TcpApp(QWidget *parent = 0);
21     ~TcpApp();
22 
23 private slots:
24     void on_severRB_clicked();//選擇做爲服務器
25 
26     void on_clientRB_clicked();//選擇做爲客戶端
27 
28     void on_StartBt_clicked();//啓動服務器或連接客戶端
29 
30     void on_closeBt_clicked();//關閉服務器或斷開客戶端
31 
32     void on_onlineUserList_doubleClicked(const QModelIndex &index);//選擇給哪一個客戶端發送數據
33 
34     void on_autoCB_clicked(bool checked);//選擇自動發送仍是手動發送
35 
36     void on_sendMsgBt_clicked();//發送信息
37 
38     //服務器
39     void accept_connect();//與newconnection信號關聯
40     void recv_data(); //接收數據
41 
42      void auto_time_send();//定時器定時發送數據
43 
44      void client_disconnect();//關聯掉線信號
45      void connect_suc();//檢測客戶端鏈接成功信號
46 
47      void on_clearRcvBt_clicked();
48 
49      void on_clearSendBt_clicked();
50 
51 private:
52     Ui::TcpApp *ui;
53     QTimer *mTimer;//定時發送數據
54     QTcpServer *mServer;
55     QTcpSocket *mSocket;
56     QVector<QTcpSocket*> clients; //存儲全部在線客戶端(容器)
57 
58     bool isServer;//標誌位,true爲服務器,false爲客戶端
59 
60     //保存接收和發送數據的字節數
61     quint64 recvSize;
62     quint64 sendSize;
63 
64     qint16 onNum;
65     bool isCheckServer;//判斷是否選擇了服務器
66     bool isCheckClient;//判斷是否選擇了客戶端
67 
68 
69 };
70 
71 #endif // TCPAPP_H
View Code

源文件:tcpapp.cpp

  1 #include "tcpapp.h"
  2 #include "ui_tcpapp.h"
  3 
  4 TcpApp::TcpApp(QWidget *parent) :
  5     QMainWindow(parent),
  6     ui(new Ui::TcpApp),
  7     onNum(0)
  8 {
  9     ui->setupUi(this);
 10     recvSize = 0;
 11     sendSize = 0;
 12     //初始化定時器
 13     mTimer = new QTimer();
 14     connect(mTimer,SIGNAL(timeout()),this,SLOT(auto_time_send()));
 15 }
 16 
 17 TcpApp::~TcpApp()
 18 {
 19     delete ui;
 20 }
 21 
 22 //與newconnection信號關聯
 23 void TcpApp::accept_connect()
 24 {
 25     mSocket = mServer->nextPendingConnection(); //返回與客戶端鏈接通訊的套接字
 26 
 27     //關聯接收數據信號
 28     connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
 29     //關聯掉線信號
 30     connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
 31 
 32     //上線用戶添加到客戶列表容器
 33     clients.append(mSocket);
 34     //把用戶添加到界面列表中
 35     QString ip = mSocket->peerAddress().toString().remove("::ffff:");//去除客戶端中多餘的字符
 36     ui->onlineUserList->addItem(ip);
 37 
 38     //在線數量添加
 39     onNum++;
 40     ui->onlineUserCount->setText(QString::number(onNum));//顯示在線數
 41 
 42 }
 43 
 44 //接收數據
 45 void  TcpApp::recv_data()
 46 {
 47       QTcpSocket *obj = (QTcpSocket*)sender();
 48       //獲取發送數據端的IP
 49       QString ip = obj->peerAddress().toString();
 50       ip.remove("::ffff:");
 51       QString msg = obj->readAll();
 52       ui->receiveList->addItem(ip+":"+msg);//顯示接收到的數據
 53       recvSize += msg.size();//統計接收到的數據的字節數
 54       ui->receiveNumLabel->setText(QString::number(recvSize));
 55 }
 56 
 57 void TcpApp::client_disconnect()
 58 {
 59     QTcpSocket *obj = (QTcpSocket*)sender();//獲取掉線對象
 60     if(isServer)
 61     {
 62         int row = clients.indexOf(obj);//找到掉線對象的內容所在的行
 63         QListWidgetItem *item = ui->onlineUserList->takeItem(row);//從界面列表中去除找到的一行內容
 64         delete item;
 65         clients.remove(row);//從容器中刪除對象
 66 
 67         //掉線時刪除在線數量
 68         onNum--;
 69         ui->onlineUserCount->setText(QString::number(onNum));
 70     }
 71     else
 72     {
 73         ui->StartBt->setEnabled(true);//斷開鏈接的時候從新啓用開始按鈕
 74     }
 75 }
 76 
 77 
 78 //客戶端鏈接成功
 79 void TcpApp::connect_suc()
 80 {
 81     ui->StartBt->setEnabled(false);//鏈接成功則禁用開始按鈕
 82 }
 83 //定時器定時發送數據
 84 void TcpApp::auto_time_send()
 85 {
 86     quint64 len = mSocket->write(ui->sendMsgEdit->toPlainText().toUtf8());
 87     if(len > 0)
 88     {
 89         sendSize += len;//統計發送的字節數
 90         ui->sendNumLabel->setText(QString::number(sendSize));//把發送的字節數顯示到sendNumLabel上
 91 
 92     }
 93 }
 94 
 95 //選擇做爲服務器
 96 void TcpApp::on_severRB_clicked()
 97 {
 98     this->isCheckServer = true;
 99     this->isServer = true;
100     //獲取本地ip顯示在IpEdit中
101    ui->IpEdit->setText(QHostAddress(QHostAddress::LocalHost).toString());
102    ui->IpEdit->setEnabled(false);//關閉ip輸入編輯器
103    this->isCheckClient = false;
104 
105 }
106 
107 //選擇做爲客戶端
108 void TcpApp::on_clientRB_clicked()
109 {
110     this->isCheckClient = true;
111     this->isServer = false;
112     ui->IpEdit->setEnabled(true);//打開ip輸入編輯器
113     this->isCheckServer = false;
114 
115 }
116 
117 //啓動服務器或者連接服務器
118 void TcpApp::on_StartBt_clicked()
119 {
120     if(isServer) //服務器
121     {
122         mServer = new QTcpServer();
123         //關聯新客戶端連接信號
124         connect(mServer,SIGNAL(newConnection()),this,SLOT(accept_connect()));
125         mServer->listen(QHostAddress::Any,ui->PortEdit->text().toInt());//啓動服務器監聽
126         ui->StartBt->setEnabled(false);//開始按鈕禁用
127     }
128     if(isServer == false) //客戶端
129     {
130         mSocket = new QTcpSocket();
131         //檢測連接成功信號
132         connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));
133         //設置服務器的 ip和端口號
134         mSocket->connectToHost(ui->IpEdit->text(),ui->PortEdit->text().toInt());
135 
136 
137         //關聯接收數據信號
138         connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
139         //關聯掉線信號
140         connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
141     }
142 
143     if(isCheckServer == false && isCheckClient == false)//若是兩個都沒選擇
144     {
145         QMessageBox::warning(this,"提示","請選擇服務器或者客戶端");
146         ui->StartBt->setEnabled(true);
147         return;
148     }
149 
150     if(isCheckServer)//選擇了服務器
151     {
152        if(ui->PortEdit->text().isEmpty() || ui->PortEdit->text() == "請輸入端口號")
153        {
154            QMessageBox::warning(this,"提示","請輸入端口號");
155            ui->StartBt->setEnabled(true);
156            return;
157        }
158     }
159 
160     if(isCheckClient)//選擇了客戶端
161     {
162         if(ui->IpEdit->text().isEmpty() || ui->IpEdit->text() == "請輸入ip" || ui->IpEdit->text() == "請輸入端口號")
163         {
164             QMessageBox::warning(this,"提示","請輸入ip和端口號");
165             ui->StartBt->setEnabled(true);
166             return;
167         }
168     }
169 
170 }
171 
172 //關閉服務器或者斷開
173 void TcpApp::on_closeBt_clicked()
174 {
175     if(isServer)//服務器
176     {
177         for(int i=0;i<clients.count();i++)
178         {
179              clients.at(i)->close();//關閉全部客戶端
180         }
181 
182         //關閉全部服務器以後開始按鈕才能啓用
183         mServer->close();
184         ui->StartBt->setEnabled(true);
185     }
186     else //客戶端
187     {
188         mSocket->close();//關閉客戶端
189         ui->StartBt->setEnabled(true);//啓用開始按鈕
190     }
191 
192 }
193 
194 //雙擊選擇要發送的客戶端
195 void TcpApp::on_onlineUserList_doubleClicked(const QModelIndex &index)
196 {
197     mSocket = clients.at(index.row());
198 
199 }
200 
201 //自動發送數據
202 void TcpApp::on_autoCB_clicked(bool checked)
203 {
204     if(checked)
205 
206     {
207         if(ui->autoTimeEdit->text().toInt() <= 0)
208         {
209             QMessageBox::warning(this,"提示","請輸入時間值ms");
210             ui->autoCB->setChecked(false);//把按鈕從新置於沒選中的狀態
211             return;
212         }
213         mTimer->start(ui->autoTimeEdit->text().toInt());//啓動定時器
214     }
215     else
216     {
217         mTimer->stop();//中止定時器
218     }
219 
220 }
221 
222 //手動發送數據
223 void TcpApp::on_sendMsgBt_clicked()
224 {
225     auto_time_send();
226 
227 }
228 
229 //清空接收區
230 void TcpApp::on_clearRcvBt_clicked()
231 {
232     ui->receiveNumLabel->clear();
233     this->recvSize = 0;
234     ui->receiveNumLabel->setText(QString::number(recvSize));
235 }
236 
237 //清空發送區
238 void TcpApp::on_clearSendBt_clicked()
239 {
240     ui->sendNumLabel->clear();
241     this->sendSize = 0;
242     ui->sendNumLabel->setText(QString::number(sendSize));
243 }
View Code

界面文件tcpapp.ui以下圖

 

此外這裏還使用到了容器,在這裏講講容器的使用

一、定義容器對象

QVector<QTcpSocket*> clients; //存儲全部在線客戶端(容器)
  解釋:QTcpSocke*  容器的類型
       clients  容器名

二、往容器中添加成員

//上線用戶添加到客戶列表容器
 clients.append(mSocket); 

三、尋找某個成員在容器中位置

 int row = clients.indexOf(obj);//找到掉線對象的內容所在的行

四、從容器中刪除成員

  clients.remove(row);//從容器中刪除成員
相關文章
相關標籤/搜索