目录
一、说明
1、Qt提供TCP/UDP的套接字通信,使用时需要添加网络模块和包含对应的头文件。
①、 往项目文件中添加network模块:QT += network 。
②、 在源代码中包含有文件:#include
2、套接字的分类:
①、TCP 套接字类(QTcpSocket)
②、UDP 套接字类(QUdpSocket)
Qt服务器端设计流程(TCP)
linux 与 Qt 的 TCP 服务端流程对比
- 在 Qt 中 listen 相当于 linux 中 bind 和 listen 两者结合在一起,是 Qt 对 linux 的更高层封装。
QTcpServer 服务器类
Header: | #include |
---|---|
qmake: | QT += network 模块 |
Inherits: | QObject |
Inherited By: | QSctpServer |
构造函数:
QTcpServer(QObject *parent = nullptr)
函数接口:
//绑定并监听
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)
QHostAddress:服务器的IP地址
👉QHostAddress::Any 监听本地所有地址
port:端口号
//接收客户端链接请求,产生新对象
QTcpSocket *QTcpServer::nextPendingConnection()
⚡信号: 每当有新的链接请求就会发送该信号
void newConnection()
1.创建网络服务器对象
QTcpServer *server = new QTcpServer(this);
2.绑定并监听
bool ret = server->listen(QHostAddress::Any,9999);
if(ret)
{
ui->statusbar->showMessage("服务器监听成功");
}else
{
ui->statusbar->showMessage("服务器监听失败");
}
3.处理客户端的链接请求
//关联新的链接请求信号
connect(server,SIGNAL(newConnection()),this,SLOT(new_connect()));
//槽函数
void MainWindow::new_connect()
{
qDebug() << "有新的客户端链接,请处理" << endl;
//产生新对象
QTcpSocket *clien = server->nextPendingConnection();
qDebug() << "对方的IP信息:" << clien->peerAddress().toString();
qDebug() << "对方的端口信息:" << clien->peerPort();
}
4.进行读写通信
//1.发送数据
clien->write(msg.toUtf8());
//2.关联信号与槽接收数据
connect(clien,SIGNAL(readyRead()),this,SLOT(readmsg()));
void MainWindow::readmsg()
{
//读取所有网络数据
QString msg = clien->readAll();
}
5. 示例
UI 设计
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtNetwork>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_start_clicked_clicked();
void on_pushButton_send_clicked_clicked();
private:
Ui::MainWindow *ui;
//tcp服务器
QTcpServer *mServer;
QTcpSocket *mSocket;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
//启动TCP服务器
void MainWindow::on_pushButton_start_clicked_clicked()
{
//1.构造tcp服务器对象
mServer = new QTcpServer(this);
//2.连接客户端连接上来的信号
QObject::connect(mServer,&QTcpServer::newConnection,this,[&](){
//获取客户端连接上来的套接字
mSocket = mServer->nextPendingConnection();
//打印客户端的地址
QHostAddress c_addr = mSocket->peerAddress();
ui->textBrowser->append(c_addr.toString()+"连接上来!\n");
//使能发送输入框和按钮
ui->lineEdit->setEnabled(true);
ui->pushButton_send_clicked->setEnabled(true);
//连接readyRead信号和槽
QObject::connect(mSocket,&QTcpSocket::readyRead,this,[&](){
//接收数据
QByteArray arr = mSocket->readAll();
//转换成字符串显示
ui->textBrowser->append("rcv:"+QString(arr)+"\n");
});
});
//3.监听
mServer->listen(QHostAddress::Any,ui->spinBox->value());
//连接回车发送的信号和槽
QObject::connect(ui->lineEdit, &QLineEdit::returnPressed, this, &MainWindow::on_pushButton_send_clicked_clicked);
//禁止端口号和启动按钮
ui->spinBox->setEnabled(false);
ui->pushButton_start_clicked->setEnabled(false);
}
//发送
void MainWindow::on_pushButton_send_clicked_clicked()
{
//获取发送的数据
QString str = ui->lineEdit->text();
//转换成QByteArray
QByteArray arr;
arr.append(str);
//发送
mSocket->write(arr);
//显示发送的内容
ui->textBrowser->insertPlainText("send:"+str+"\n");
//清空lineEdit
ui->lineEdit->clear();
}
Qt 客户端设计流程(TCP)
QTcpSocket 客户端类
Header: | #include |
---|---|
qmake: | QT += network 💥.pro记得加模块 |
Inherits: | QAbstractSocket |
Inherited By: | QSctpSocket and QSslSocket |
构造函数:
QTcpSocket(QObject *parent = nullptr)
函数接口:
connectToHost(const QHostAddress &, quint16) //链接服务器
QHostAddress:服务器IP地址
quint16 :服务器端口号
//读取操作
read(char *, qint64 )
char *: 读取数据的存储地址
qint64: 读取数据的大小
QByteArray read(qint64 maxSize) //读取数据并返回字节数组
QByteArray readAll() //读取所有数据并返回字节数组
//写操作
qint64 write(const QByteArray &byteArray) //写入字节数组
qint64 write(const char *data) //写入字符串
qint64 write(const char *data, qint64 maxSize) //写入字符串并设置大小为 maxSize
//关闭通信
void close()
1.创建网络通信对象
//1.创建网络socket
QTcpSocket *clien = new QTcpSocket(this);
2.链接服务器
//链接IP为 "192.168.73.1" 端口为 8888 的服务器
clien->connectToHost("192.168.73.1",8888);
3.write 发送数据
qint64 write(const QByteArray &byteArray) //写入字节数组
qint64 write(const char *data) //写入字符串
qint64 write(const char *data, qint64 maxSize) //写入字符串并设置大小为 maxSize
//发送数据例子
clien->write("hello");
clien->write("1234567",2);
QString msg = "哈哈哈";
clien->write(msg.toUtf8());
4.😱(难点)read 接收数据
在QT中所有的阻塞IO接口,都是使用信号与槽解决的! 每当阻塞IO有数据时,系统就会发送相对应的信号。
[signal] void QIODevice::readyRead() 有数据可读信号! 只要关联该信号,处理数据即可!
-------读取数据例子-------
connect(clien,&QTcpSocket::readyRead,this,[&](){
//读取所有网络数据
QString msg = clien->readAll();
qDebug() << msg;
});
QUdpSocket 类
Header: | #include |
---|---|
qmake: | QT += network模块 |
Inherits: | QAbstractSocket |
//构造函数
QUdpSocket(QObject *parent = nullptr)
//函数接口
qint64 writeDatagram (const char *data, //数据的缓存区
qint64 size, //发送数据的大小
const QHostAddress &address, //接收端的IP地址
quint16 port) //接收端端口
qint64 readDatagram(char *data, //数据的缓存地址
qint64 maxSize, //接收数据大小
QHostAddress *address = nullptr, //对方的IP地址信息
quint16 *port = nullptr) //对方的端口信息
//读取数据包并返回数据包类
QNetworkDatagram receiveDatagram(qint64 maxSize = -1)
//判断是否有数据报可读
bool QUdpSocket::hasPendingDatagrams() const
QT——》IP地址类QHostAddress
QHostAddress(const QString &address) //字符串转换为IP地址类
转换例子👉 QHostAddress("192.168.73.1")
UDP发送端
1.创建UDP对象
QUdpSocket *udp_send= new QUdpSocket(this);
2.发送UDP数据报
//2.发送一个UDP数据报
udp_send->writeDatagram("hello",5,QHostAddress("192.168.73.1"),8888);
UDP 接收端
1.创建UDP对象
QUdpSocket *udp_recv = new QUdpSocket(this);
2.绑定接收端地址信息
if(udp_recv->bind(QHostAddress::Any,8888))
{
ui->statusbar->showMessage("绑定成功");
}else
{
ui->statusbar->showMessage("绑定失败");
}
3.读取数据
信号:当有数据来临时,就会发送该信号
void readyRead() ;
connect(udp_recv,&QUdpSocket::readyRead,this,[&](){
char buf[1024]={0};
udp_recv->readDatagram(buf,1024,NULL,NULL);
qDebug() << buf;
});
-----------------------------------------------------------------
QNetworkDatagram 数据报类
QByteArray data() const //数据
QHostAddress senderAddress() const //发送者地址
int senderPort() const //发送者端口
//3.关联信号与槽
connect(udp_recv, &QUdpSocket::readyRead,this, &MainWindow::readPendingDatagrams);
//读取数据报槽函数
void MainWindow::readPendingDatagrams()
{
while (udp_recv->hasPendingDatagrams()) {
QNetworkDatagram datagram = udp_recv->receiveDatagram();
//转换数据报获取数据
QString ip = datagram.senderAddress().toString();
int port = datagram.senderPort();
QString msg = datagram.data();
ui->textBrowser->append(QString("%1 %2 %3").arg(ip).arg(port).arg(msg));
}
}