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
源文件: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 }
界面文件tcpapp.ui如下图
此外这里还使用到了容器,在这里讲讲容器的使用
1、定义容器对象
QVector<QTcpSocket*> clients; //存储所有在线客户端(容器) 解释:QTcpSocke* 容器的类型 clients 容器名
2、往容器中添加成员
//上线用户添加到客户列表容器 clients.append(mSocket);
3、寻找某个成员在容器中位置
int row = clients.indexOf(obj);//找到掉线对象的内容所在的行
4、从容器中删除成员
clients.remove(row);//从容器中删除成员