QT之TCP通信

QT中可以通过TCP协议让服务器和客户端之间行通信。所以下面我就围绕服务器和客户端来写。

这是我们写服务器和客户端的具体流程:

A、服务器:      

         1.创建QTcpServer对象
         2.启动服务器(监听)调用成员方法listen(QHostAddress::Any,端口号)
         3.当有客户端链接时候会发送newConnection信号,触发槽函数接受链接(得到一个与客户端通信的套接字QTcpSocket)
         4.QTcpsocket发送数据用成员方法write,
         5.读数据当客户端有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据

B、客户端  :  

        1.创建QTcpSocket对象
        2.链接服务器connectToHost(QHostAddress("ip"),端口号)
        3.QTcpsocket发送数据用成员方法write,
        4.读数据当对方有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据

 

我们需要调用到的头文件有两个

#include <QTcpServer>  
#include <QTcpSocket>

我们先要在工程文件中加入network

QT       += core gui network

下面我们来看看服务器程序步骤:

1、初始化服务器server对象

mServer = new QTcpServer();

2、启动监听服务器

  mServer->listen(QHostAddress::Any,9988);//9988为端口号

3、当有客户端链接时候会发送newConnection信号,触发槽函数接受链接(得到一个与客户端通信的套接字QTcpSocket)

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

4、发送数据

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

5、读数据当客户端有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据

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

6、连接多个客户端

 //可以实现同时读取多个客户端发送过来的消息
 QTcpSocket *obj = (QTcpSocket*)sender();

7、检测掉线

 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 }

 

说完服务器那我们继续来看看客户端是怎么实现的:

1、创建QTcpSocket对象

 mSocket = new QTcpSocket();

2、链接服务器connectToHost(QHostAddress("ip"),端口号),连接服务器ip和端口号

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

3、发送数据

//取发送信息编辑框内容
QString msg = ui->sendEdit->toPlainText();
mSocket->write(msg.toUtf8());//转编码

4、检测链接成功信号关联槽函数

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

5、检测掉线信号

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

6、服务器和客户端关闭都可以使用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如下图

 

此外这里还使用到了容器,在这里讲讲容器的使用

1、定义容器对象

QVector<QTcpSocket*> clients; //存储所有在线客户端(容器)
  解释:QTcpSocke*  容器的类型
       clients  容器名

2、往容器中添加成员

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

3、寻找某个成员在容器中位置

 int row = clients.indexOf(obj);//找到掉线对象的内容所在的行

4、从容器中删除成员

  clients.remove(row);//从容器中删除成员

 

posted @ 2017-12-10 23:47  沙漠里的孤鲸  阅读(29419)  评论(3编辑  收藏  举报