# TCP 通信
Qt 需要
network
模块实现套接字通信,在 pro 文件中提前加入。所有通信函数与 C++ 封装 TCP 通信类似。
# 通信与函数
# TCP 通信案例
# 服务端
# UI
# server.h
#ifndef SERVER_H | |
#define SERVER_H | |
#include <QMainWindow> | |
#include <QTcpSocket> | |
#include <QTcpServer> | |
namespace Ui { | |
class server; | |
} | |
class server : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
explicit server(QWidget *parent = nullptr); | |
~server(); | |
private slots: | |
void on_startServer_clicked(); | |
void on_sendMsg_clicked(); | |
private: | |
Ui::server *ui; | |
QTcpServer* m_server; | |
QTcpSocket* m_tcp; | |
}; | |
#endif // SERVER_H |
# server.cpp
#include "server.h" | |
#include "ui_server.h" | |
server::server(QWidget *parent) : | |
QMainWindow(parent), | |
ui(new Ui::server) | |
{ | |
ui->setupUi(this); | |
setWindowTitle("TCP - 服务器"); | |
// 创建 QTcpServer 对象 | |
m_server = new QTcpServer(this); | |
// 检测是否有新链接 | |
connect(m_server,&QTcpServer::newConnection,this,[=]() | |
{ | |
m_tcp = m_server->nextPendingConnection(); // 获取 TCP 连接 | |
ui->m_status->setText("已连接"); | |
ui->records->append("成功和客户端建立了新连接"); | |
// 客户端发送过来了数据 | |
connect(m_tcp,&QTcpSocket::readyRead,this,[=]() | |
{ | |
// 接受数据 | |
QString recvMsg=m_tcp->readAll(); | |
ui->records->append("客户端say:" + recvMsg); | |
ui->records->setAlignment(Qt::AlignRight); | |
}); | |
// 客户端断开了连接 | |
connect(m_tcp,&QTcpSocket::disconnected,this,[=]() | |
{ | |
ui->records->append("客户端已经断开了连接"); | |
m_tcp->deleteLater(); | |
ui->m_status->setText("已断开"); | |
}); | |
}); | |
} | |
server::~server() | |
{ | |
delete ui; | |
} | |
void server::on_startServer_clicked() | |
{ | |
unsigned short port = ui->port->text().toInt(); | |
// 设置服务器监听 | |
m_server->listen(QHostAddress::LocalHost,port); | |
ui->startServer->setEnabled(false); | |
} | |
void server::on_sendMsg_clicked() | |
{ | |
QString sendMsg = ui->msg->toPlainText(); | |
m_tcp->write(sendMsg.toUtf8()); | |
ui->records->append("服务器Say:" + sendMsg); | |
ui->records->setAlignment(Qt::AlignLeft); | |
ui->msg->clear(); | |
} |
# 客户端
# UI
# `client.h``
#ifndef CLIENT_H | |
#define CLIENT_H | |
#include <QMainWindow> | |
#include <QTcpSocket> | |
namespace Ui { | |
class client; | |
} | |
class client : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
explicit client(QWidget *parent = nullptr); | |
~client(); | |
private slots: | |
void on_connect_clicked(); | |
void on_close_clicked(); | |
void on_send_clicked(); | |
private: | |
Ui::client *ui; | |
QTcpSocket* m_tcp; | |
}; | |
#endif // CLIENT_H |
# client.cpp
#include "client.h" | |
#include "ui_client.h" | |
client::client(QWidget *parent) : | |
QMainWindow(parent), | |
ui(new Ui::client) | |
{ | |
ui->setupUi(this); | |
setWindowTitle("TCP - 客户端"); | |
// 创建通信的套接字对象 | |
ui->ip->setText("127.0.0.1"); | |
m_tcp = new QTcpSocket(this); | |
ui->close->setEnabled(false); | |
// 检测是否和服务器连接成功 | |
connect(m_tcp,&QTcpSocket::connected,this,[=]() | |
{ | |
ui->rec->append("恭喜,服务器连接成功!"); | |
ui->status->setText("已连接"); | |
}); | |
// 检测服务器是都恢复了数据 | |
connect(m_tcp,&QTcpSocket::readyRead,[=]() | |
{ | |
QByteArray recvMsg = m_tcp->readAll(); | |
ui->rec->append("服务器say:"+recvMsg); | |
ui->rec->setAlignment(Qt::AlignRight); | |
}); | |
// 检测服务器是否断开了连接 | |
connect(m_tcp,&QTcpSocket::disconnected,this,[=]() | |
{ | |
ui->rec->append("服务器已经断开了连接"); | |
ui->connect->setEnabled(true); | |
ui->close->setEnabled(false); | |
}); | |
} | |
client::~client() | |
{ | |
delete ui; | |
} | |
void client::on_connect_clicked() | |
{ | |
QString ip = ui->ip->text(); | |
unsigned short port = ui->port->text().toInt(); | |
// 连接服务器 | |
m_tcp->connectToHost(ip,port); | |
ui->connect->setEnabled(false); | |
ui->close->setEnabled(true); | |
} | |
void client::on_close_clicked() | |
{ | |
m_tcp->close(); | |
ui->connect->setEnabled(true); | |
ui->close->setEnabled(false); | |
} | |
void client::on_send_clicked() | |
{ | |
QString sendMsg = ui->msg->toPlainText(); | |
m_tcp->write(sendMsg.toUtf8()); | |
ui->rec->append("客户端Say:"+sendMsg); | |
ui->rec->setAlignment(Qt::AlignLeft); | |
ui->msg->clear(); | |
} |
# UDP 通信
Qt 的客户端和服务端不区分,实现双向通信,彼此即是服务端,也是接收端
# UDP
通信案例
# 服务端
# UI
# server.h
#ifndef UDF_SERVER_H | |
#define UDF_SERVER_H | |
#include <QMainWindow> | |
#include <QUdpSocket> | |
namespace Ui { | |
class udf_server; | |
} | |
class udf_server : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
explicit udf_server(QWidget *parent = nullptr); | |
~udf_server(); | |
private slots: | |
void on_send_clicked(); | |
void on_connect_clicked(); | |
private: | |
Ui::udf_server *ui; | |
QUdpSocket* server; | |
}; | |
#endif // UDF_SERVER_H |
# server.cpp
#include "udf_server.h" | |
#include "ui_udf_server.h" | |
udf_server::udf_server(QWidget *parent) : | |
QMainWindow(parent), | |
ui(new Ui::udf_server) | |
{ | |
ui->setupUi(this); | |
setWindowTitle("UDP 服务器"); | |
server = new QUdpSocket(this); | |
ui->ip->setText("127.0.0.1"); | |
ui->port_self->setText("8888"); // 当前主机绑定端口号 | |
// 读取对方发送的数据 | |
connect(server,&QUdpSocket::readyRead,this,[&]() | |
{ | |
QByteArray datagram; | |
datagram.resize(server->pendingDatagramSize()); | |
server->readDatagram(datagram.data(),datagram.size()); // 读数据 | |
ui->recev->append("对方:"+datagram); | |
}); | |
} | |
udf_server::~udf_server() | |
{ | |
delete ui; | |
} | |
void udf_server::on_send_clicked() | |
{ | |
// 发送环节设置 | |
// 读取要发送的内容 | |
QByteArray datagram = ui->send_text->toPlainText().toUtf8(); | |
// 发送的信息,大小,IP 和端口 | |
server->writeDatagram(datagram.data(),datagram.size(),QHostAddress(ui->ip->text()),ui->port->text().toInt()); | |
ui->recev->append("本机" + ui->send_text->toPlainText()); | |
ui->send_text->clear(); | |
} | |
// 启动服务器 | |
void udf_server::on_connect_clicked() | |
{ | |
// 当前服务端绑定端口号 | |
server->bind(QHostAddress(ui->ip->text()),ui->port_self->text().toInt()); // 设置当前主机绑定的端口 | |
ui->connect->setEnabled(false); | |
} |
# 客户端
# UI
# client.h
#ifndef UDF_CLIENT_H | |
#define UDF_CLIENT_H | |
#include <QMainWindow> | |
#include <QUdpSocket> | |
namespace Ui { | |
class udf_client; | |
} | |
class udf_client : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
explicit udf_client(QWidget *parent = nullptr); | |
~udf_client(); | |
private slots: | |
void on_connect_clicked(); | |
void on_send_clicked(); | |
private: | |
Ui::udf_client *ui; | |
QUdpSocket * recever; | |
}; | |
#endif // UDF_CLIENT_H |
# client.cpp
#include "udf_client.h" | |
#include "ui_udf_client.h" | |
udf_client::udf_client(QWidget *parent) : | |
QMainWindow(parent), | |
ui(new Ui::udf_client) | |
{ | |
ui->setupUi(this); | |
setWindowTitle("UDP 绑定IP"); | |
ui->ip->setText("127.0.0.1"); | |
recever = new QUdpSocket(this); | |
} | |
udf_client::~udf_client() | |
{ | |
delete ui; | |
} | |
void udf_client::on_connect_clicked() | |
{ | |
// 点击连接之后,进入接受状态 | |
recever->bind(QHostAddress(ui->ip->text().toInt()),ui->port->text().toInt()); // 绑定 IP | |
connect(recever,&QUdpSocket::readyRead,this,[&]() | |
{ | |
QByteArray datagram; | |
datagram.resize(recever->pendingDatagramSize()); | |
recever->readDatagram(datagram.data(),datagram.size()); // 读数据 | |
ui->rev->append("对方:"+datagram); | |
}); | |
ui->connect->setEnabled(false); | |
//ui->rev->setEnabled(false); | |
} | |
void udf_client::on_send_clicked() | |
{ | |
// 发送环节设置 | |
// 读取要发送的内容 | |
QByteArray datagram = ui->send_test->toPlainText().toUtf8(); | |
// 发送的信息,大小,IP 和端口 | |
recever->writeDatagram(datagram.data(),datagram.size(),QHostAddress(ui->ip->text()),ui->port_other->text().toInt()); | |
ui->rev->append("本机" + ui->send_test->toPlainText()); | |
ui->send_test->clear(); | |
} |
# TCP 文件传输
客户端连接服务器,可以实现多种文件向服务器进行发送
# 服务端 ` 接收端
# UI
# server.h
#ifndef SERVER_H | |
#define SERVER_H | |
#include <QMainWindow> | |
#include <QTcpSocket> | |
#include <QTcpServer> | |
#include <QFile> | |
#include <QTimer> | |
#include <QFileDialog> | |
#include <QFileInfo> | |
#include <QDebug> | |
#include <QMessageBox> | |
namespace Ui { | |
class server; | |
} | |
class server : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
explicit server(QWidget *parent = nullptr); | |
~server(); | |
private slots: | |
void on_startServer_clicked(); | |
private: | |
Ui::server *ui; | |
QTcpServer* m_server; | |
QTcpSocket* m_tcp; | |
bool headinfo = true; | |
QString filename; | |
qint64 filesize; | |
qint64 recvsize; | |
QFile file; | |
}; | |
#endif // SERVER_H |
# server.cpp
#include "server.h" | |
#include "ui_server.h" | |
server::server(QWidget *parent) : | |
QMainWindow(parent), | |
ui(new Ui::server) | |
{ | |
ui->setupUi(this); | |
setWindowTitle("TCP - 服务器接受文件"); | |
// 创建 QTcpServer 对象 | |
m_server = new QTcpServer(this); | |
// 客户端断开了连接 | |
// connect(m_tcp,&QTcpSocket::disconnected,this,[=]() | |
// { | |
// m_tcp->deleteLater(); | |
// ui->m_status->setText ("已断开"); | |
// }); | |
} | |
server::~server() | |
{ | |
delete ui; | |
} | |
void server::on_startServer_clicked() | |
{ | |
unsigned short port = ui->port->text().toInt(); | |
// 设置服务器监听 | |
m_server->listen(QHostAddress::LocalHost,port); | |
// 检测是否有新链接 | |
connect(m_server,&QTcpServer::newConnection,this,[&]() | |
{ | |
m_tcp = m_server->nextPendingConnection(); // 获取 TCP 连接 | |
ui->m_status->setText("已连接"); | |
// 客户端发送过来了数据 | |
connect(m_tcp,&QTcpSocket::readyRead,this,[&]() | |
{ | |
// 读取数据 | |
QByteArray array = m_tcp->readAll(); | |
if(headinfo) | |
{ | |
headinfo = false; | |
recvsize = 0; | |
filename = QString(array).section("**",0,0); // 起始,结束 | |
filesize = QString(array).section("**",1,1).toInt(); | |
file.setFileName(filename); // 设置文件 | |
file.open(QIODevice::WriteOnly);// 只读的方式打开文件 | |
// 设置传输的进度条 | |
ui->progressBar->setMinimum(0); | |
ui->progressBar->setMaximum(filesize / 1024); | |
ui->progressBar->setValue(0); // 设置当前值为 0 | |
} | |
else | |
{ | |
// 处理数据文件 | |
qint64 length = file.write(array); | |
if(length > 0) | |
{ | |
recvsize +=length; | |
} | |
ui->progressBar->setValue(recvsize / 1024); | |
qDebug() <<"接收大小"<< recvsize <<"文件大小"<< filesize; | |
if(recvsize == filesize) | |
{ | |
QMessageBox::information(this,"完成","文件接受完成"); | |
file.close(); | |
} | |
} | |
}); | |
}); | |
} |
# 客户端 发送端
# UI
# client.h
#ifndef CLIENT_H | |
#define CLIENT_H | |
#include <QMainWindow> | |
#include <QTcpSocket> | |
#include <QFile> | |
#include <QTimer> | |
namespace Ui { | |
class client; | |
} | |
class client : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
explicit client(QWidget *parent = nullptr); | |
~client(); | |
private slots: | |
void on_connect_clicked(); | |
void on_close_clicked(); | |
void on_send_clicked(); | |
void on_open_clicked(); | |
private: | |
Ui::client *ui; | |
QTcpSocket* m_tcp; | |
QString filename; | |
qint64 filesize; | |
QFile file; | |
QTimer *myTimer; | |
}; | |
#endif // CLIENT_H |
# client.cpp
#include "client.h" | |
#include "ui_client.h" | |
#include <QFileDialog> | |
#include <QFileInfo> | |
#include <QDebug> | |
client::client(QWidget *parent) : | |
QMainWindow(parent), | |
ui(new Ui::client) | |
{ | |
ui->setupUi(this); | |
setWindowTitle("TCP - 客户端上传文件"); | |
// 创建通信的套接字对象 | |
ui->ip->setText("127.0.0.1"); | |
m_tcp = new QTcpSocket(this); | |
ui->close->setEnabled(false); | |
// 检测是否和服务器连接成功 | |
connect(m_tcp,&QTcpSocket::connected,this,[=]() | |
{ | |
//ui->rec->append ("恭喜,服务器连接成功!"); | |
ui->status->setText("已连接"); | |
ui->connect->setEnabled(false); | |
ui->close->setEnabled(true); | |
}); | |
// 检测服务器是都恢复了数据 | |
// connect(m_tcp,&QTcpSocket::readyRead,[=]() | |
// { | |
// QByteArray recvMsg = m_tcp->readAll(); | |
// ui->rec->append ("服务器 say:"+recvMsg); | |
// ui->rec->setAlignment(Qt::AlignRight); | |
// }); | |
// 检测服务器是否断开了连接 | |
connect(m_tcp,&QTcpSocket::disconnected,this,[=]() | |
{ | |
//ui->rec->append ("服务器已经断开了连接"); | |
ui->status->setText("未连接"); | |
ui->connect->setEnabled(true); | |
ui->close->setEnabled(false); | |
}); | |
myTimer = new QTimer(this); | |
connect(myTimer,&QTimer::timeout,this,[&]() | |
{ | |
myTimer->stop(); // 关闭定时器 | |
qint64 sendSize =0; | |
qint64 len; | |
do{ | |
char buf[4*1024] = {0}; | |
len = file.read(buf,sizeof(buf)); // 每次读取的空间 | |
m_tcp->write(buf,len); // 读取的文件缓冲区放到 buf 里面 | |
sendSize +=len; | |
ui->progressBar->setValue(sendSize / 1024); | |
}while(len >0); | |
if(sendSize == filesize) | |
{ | |
qDebug()<<"文件发送成功"; | |
file.close(); | |
m_tcp->disconnectFromHost(); | |
m_tcp->close(); | |
} | |
}); | |
} | |
client::~client() | |
{ | |
delete ui; | |
} | |
void client::on_connect_clicked() | |
{ | |
QString ip = ui->ip->text(); | |
unsigned short port = ui->port->text().toInt(); | |
// 连接服务器 | |
m_tcp->connectToHost(ip,port); | |
} | |
void client::on_close_clicked() | |
{ | |
m_tcp->close(); | |
ui->connect->setEnabled(true); | |
ui->close->setEnabled(false); | |
} | |
void client::on_send_clicked() | |
{ | |
// 点击 开始之后,发送数据,先发送头名称和大小 | |
// 文件名 ** 文件大小 | |
QString head = filename + "**" + QString::number(filesize); | |
qint64 length = m_tcp->write(head.toUtf8()); // 将头文件发送过去 | |
if(length > 0) | |
{ | |
qDebug()<<length; | |
// 发送成功 | |
myTimer->start(20); //20 毫秒之后再发,避免粘包 | |
} | |
else | |
{ | |
// 发送失败 | |
file.close();// 关闭文件 | |
} | |
} | |
void client::on_open_clicked() | |
{ | |
QString filepath = QFileDialog::getOpenFileName(this); | |
// 同时发送文件名称和文件大小 | |
QFileInfo FileData(filepath); | |
filename = FileData.fileName(); // 文件名称 | |
filesize = FileData.size(); // 文件大小 | |
qDebug()<<"文件名"<<filename <<" 文件大小:"<<filesize; | |
if(!filepath.isEmpty()) | |
{ | |
ui->file->setText(filename); | |
file.setFileName(filepath); // 设置文件 | |
file.open(QIODevice::ReadOnly);// 只读的方式打开文件 | |
} | |
// 设置传输的进度条 | |
ui->progressBar->setMinimum(0); | |
ui->progressBar->setMaximum(filesize / 1024); | |
ui->progressBar->setValue(0); // 设置当前值为 0 | |
} |