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
下面我们来看看服务器程序步骤:
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
这是客户端实现的具体代码
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
#ifndef TCPAPP_H
#define TCPAPP_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QFile>
#include <QTimer>
#include <QMessageBox>
namespace Ui {
class TcpApp;
}
class TcpApp : public QMainWindow
{
Q_OBJECT
public:
explicit TcpApp(QWidget *parent = 0);
~TcpApp();
private slots:
void on_severRB_clicked();//选择作为服务器
void on_clientRB_clicked();//选择作为客户端
void on_StartBt_clicked();//启动服务器或链接客户端
void on_closeBt_clicked();//关闭服务器或断开客户端
void on_onlineUserList_doubleClicked(const QModelIndex &index);//选择给哪个客户端发送数据
void on_autoCB_clicked(bool checked);//选择自动发送还是手动发送
void on_sendMsgBt_clicked();//发送信息
//服务器
void accept_connect();//与newconnection信号关联
void recv_data(); //接收数据
void auto_time_send();//定时器定时发送数据
void client_disconnect();//关联掉线信号
void connect_suc();//检测客户端连接成功信号
void on_clearRcvBt_clicked();
void on_clearSendBt_clicked();
private:
Ui::TcpApp *ui;
QTimer *mTimer;//定时发送数据
QTcpServer *mServer;
QTcpSocket *mSocket;
QVector<QTcpSocket*> clients; //存储所有在线客户端(容器)
bool isServer;//标志位,true为服务器,false为客户端
//保存接收和发送数据的字节数
quint64 recvSize;
quint64 sendSize;
qint16 onNum;
bool isCheckServer;//判断是否选择了服务器
bool isCheckClient;//判断是否选择了客户端
};
#endif // TCPAPP_H
源文件:tcpapp.cpp
#include "tcpapp.h"
#include "ui_tcpapp.h"
TcpApp::TcpApp(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TcpApp),
onNum(0)
{
ui->setupUi(this);
recvSize = 0;
sendSize = 0;
//初始化定时器
mTimer = new QTimer();
connect(mTimer,SIGNAL(timeout()),this,SLOT(auto_time_send()));
}
TcpApp::~TcpApp()
{
delete ui;
}
//与newconnection信号关联
void TcpApp::accept_connect()
{
mSocket = mServer->nextPendingConnection(); //返回与客户端连接通信的套接字
//关联接收数据信号
connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
//关联掉线信号
connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
//上线用户添加到客户列表容器
clients.append(mSocket);
//把用户添加到界面列表中
QString ip = mSocket->peerAddress().toString().remove("::ffff:");//去除客户端中多余的字符
ui->onlineUserList->addItem(ip);
//在线数量添加
onNum++;
ui->onlineUserCount->setText(QString::number(onNum));//显示在线数
}
//接收数据
void TcpApp::recv_data()
{
QTcpSocket *obj = (QTcpSocket*)sender();
//获取发送数据端的IP
QString ip = obj->peerAddress().toString();
ip.remove("::ffff:");
QString msg = obj->readAll();
ui->receiveList->addItem(ip+":"+msg);//显示接收到的数据
recvSize += msg.size();//统计接收到的数据的字节数
ui->receiveNumLabel->setText(QString::number(recvSize));
}
void TcpApp::client_disconnect()
{
QTcpSocket *obj = (QTcpSocket*)sender();//获取掉线对象
if(isServer)
{
int row = clients.indexOf(obj);//找到掉线对象的内容所在的行
QListWidgetItem *item = ui->onlineUserList->takeItem(row);//从界面列表中去除找到的一行内容
delete item;
clients.remove(row);//从容器中删除对象
//掉线时删除在线数量
onNum--;
ui->onlineUserCount->setText(QString::number(onNum));
}
else
{
ui->StartBt->setEnabled(true);//断开连接的时候重新启用开始按钮
}
}
//客户端连接成功
void TcpApp::connect_suc()
{
ui->StartBt->setEnabled(false);//连接成功则禁用开始按钮
}
//定时器定时发送数据
void TcpApp::auto_time_send()
{
quint64 len = mSocket->write(ui->sendMsgEdit->toPlainText().toUtf8());
if(len > 0)
{
sendSize += len;//统计发送的字节数
ui->sendNumLabel->setText(QString::number(sendSize));//把发送的字节数显示到sendNumLabel上
}
}
//选择作为服务器
void TcpApp::on_severRB_clicked()
{
this->isCheckServer = true;
this->isServer = true;
//获取本地ip显示在IpEdit中
ui->IpEdit->setText(QHostAddress(QHostAddress::LocalHost).toString());
ui->IpEdit->setEnabled(false);//关闭ip输入编辑器
this->isCheckClient = false;
}
//选择作为客户端
void TcpApp::on_clientRB_clicked()
{
this->isCheckClient = true;
this->isServer = false;
ui->IpEdit->setEnabled(true);//打开ip输入编辑器
this->isCheckServer = false;
}
//启动服务器或者链接服务器
void TcpApp::on_StartBt_clicked()
{
if(isServer) //服务器
{
mServer = new QTcpServer();
//关联新客户端链接信号
connect(mServer,SIGNAL(newConnection()),this,SLOT(accept_connect()));
mServer->listen(QHostAddress::Any,ui->PortEdit->text().toInt());//启动服务器监听
ui->StartBt->setEnabled(false);//开始按钮禁用
}
if(isServer == false) //客户端
{
mSocket = new QTcpSocket();
//检测链接成功信号
connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));
//设置服务器的 ip和端口号
mSocket->connectToHost(ui->IpEdit->text(),ui->PortEdit->text().toInt());
//关联接收数据信号
connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
//关联掉线信号
connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
}
if(isCheckServer == false && isCheckClient == false)//如果两个都没选择
{
QMessageBox::warning(this,"提示","请选择服务器或者客户端");
ui->StartBt->setEnabled(true);
return;
}
if(isCheckServer)//选择了服务器
{
if(ui->PortEdit->text().isEmpty() || ui->PortEdit->text() == "请输入端口号")
{
QMessageBox::warning(this,"提示","请输入端口号");
ui->StartBt->setEnabled(true);
return;
}
}
if(isCheckClient)//选择了客户端
{
if(ui->IpEdit->text().isEmpty() || ui->IpEdit->text() == "请输入ip" || ui->IpEdit->text() == "请输入端口号")
{
QMessageBox::warning(this,"提示","请输入ip和端口号");
ui->StartBt->setEnabled(true);
return;
}
}
}
//关闭服务器或者断开
void TcpApp::on_closeBt_clicked()
{
if(isServer)//服务器
{
for(int i=0;i<clients.count();i++)
{
clients.at(i)->close();//关闭所有客户端
}
//关闭所有服务器之后开始按钮才能启用
mServer->close();
ui->StartBt->setEnabled(true);
}
else //客户端
{
mSocket->close();//关闭客户端
ui->StartBt->setEnabled(true);//启用开始按钮
}
}
//双击选择要发送的客户端
void TcpApp::on_onlineUserList_doubleClicked(const QModelIndex &index)
{
mSocket = clients.at(index.row());
}
//自动发送数据
void TcpApp::on_autoCB_clicked(bool checked)
{
if(checked)
{
if(ui->autoTimeEdit->text().toInt() <= 0)
{
QMessageBox::warning(this,"提示","请输入时间值ms");
ui->autoCB->setChecked(false);//把按钮重新置于没选中的状态
return;
}
mTimer->start(ui->autoTimeEdit->text().toInt());//启动定时器
}
else
{
mTimer->stop();//停止定时器
}
}
//手动发送数据
void TcpApp::on_sendMsgBt_clicked()
{
auto_time_send();
}
//清空接收区
void TcpApp::on_clearRcvBt_clicked()
{
ui->receiveNumLabel->clear();
this->recvSize = 0;
ui->receiveNumLabel->setText(QString::number(recvSize));
}
//清空发送区
void TcpApp::on_clearSendBt_clicked()
{
ui->sendNumLabel->clear();
this->sendSize = 0;
ui->sendNumLabel->setText(QString::number(sendSize));
}
界面文件tcpapp.ui如下图
此外这里还使用到了容器,在这里讲讲容器的使用
1、定义容器对象
QVector<QTcpSocket*> clients; //存储所有在线客户端(容器)
解释:QTcpSocke* 容器的类型
clients 容器名
2、往容器中添加成员
//上线用户添加到客户列表容器
clients.append(mSocket);
3、寻找某个成员在容器中位置
int row = clients.indexOf(obj);//找到掉线对象的内容所在的行
4、从容器中删除成员
clients.remove(row);//从容器中删除成员
Qt5 编写网络调试助手
原文:https://www.cnblogs.com/wt88/p/14657183.html