一、Linux中的网络编程
1、子网和公网的概念
- 子网网络:局域网,只能进行内网的通信
- 公网网络:因特网,服务器等可以进行远程的通信
2、网络分层模型
4层模型:应用层、传输层、网络层、物理层
- 应用层:用户自定义的网络数据传输协议:ssh、tftp、tfp、http 等
- 传输层:tcp/udp出传输协议
- 网络层:IPV4/IPV6,3G,4G,5G等网络协议
- 物理层:光纤、路由器、网线、网卡
3、Tcp与Udp协议的区别
-
三次握手:第一次握手就是客户端给服务器端发送一个报文,第二次就是服务器收到报文之后,会应答一个报文给客户端,第三次握手就是客户端收到报文后再给服务器发送一个报文,三次握手就成功了。(进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常)
-
Tcp传输协议:可靠传输协议,Tcp需要三步握手连接,每次通信都会进行数据的校验
-
Tcp的应用:一般用于文件的传输、控制命令的传输
-
Udp传输协议:不可靠传输协议,Udp传输不需要建立连接,Udp不会进行数据校验
-
Udp的应用:一般用于多媒体的数据传传输:屏幕广播软件、视频网站、直播软件
二、TCP通信
1、QTcpSocket Class 客户端类
Header: #include 头文件
qmake: QT += network 模块
Inherits: QAbstractSocket 父类
Inherited By: QSctpSocket and QSslSocket 派生类
2、函数接口
构造函数:
QTcpSocket(QObject *parent = nullptr)
//链接服务器 IP+端口
connectToHost(const QHostAddress &, quint16, QIODevice::OpenMode )
QHostAddress : IP地址
quint16 : 端口号
------------------------------------------------------------------
//直接填写IP 地址即可链接
connectToHost(const QString &, quint16, QIODevice::OpenMode, QAbstractSocket::NetworkLayerProtocol )
例子:
socket->connectToHost("192.168.25.2",1000);
3、数据的收发
//数据的发送
write(const char *, qint64 ) //发送 qint64大的数据
write(const char *)//直接发送字符数据
write(const QByteArray &) //发生QByteArray类型的数据
//数据的接收
qint64 read(char *, qint64 ) //读取 qint64大的数据到 char * 地址 上
QByteArray read(qint64 ) //读取 qint64 大的数据 并返回
QByteArray readAll() //读取所有数据
//关联可读信号
[signal] void QIODevice::readyRead()
4、QTcpServer Class 服务器类
Header: #include
qmake: QT += network
Inherits: QObject
Inherited By: QSctpServer
5、函数接口:
构造函数:
QTcpServer(QObject *parent = nullptr)
//绑定并监听接口
bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port= 0)
QHostAddress::Any : 相当于 INADDR_ANY.自动监听本地的所有地址
port : 取值范围 0 - 65535,尽量用 1000 以后的,因为 1000前,系统占用
例子: 监听本地IP地址
server->listen(QHostAddress::Any,6666)
接收链接请求:
//服务器新的链接信号
[signal] void QTcpServer::newConnection()
//服务器 产生新的对象
[virtual] QTcpSocket*QTcpServer::nextPendingConnection()
6、数据的收发 :
//产生新的通信对象
QTcpSocket *new_socket = server->nextPendingConnection();
//通过的新的对象进行数据的收发
write(const char *, qint64 ) //发送 qint64大的数据
write(const char *)//直接发送字符数据
write(const QByteArray &) //发生QByteArray类型的数据
//接收数据
//1.关联新的对象的可读 信号
[signal] void QIODevice::readyRead()
//2.在槽函数中读取数据
qint64 read(char *, qint64 ) //读取qint64 大的数据到 char * 地址 上
QByteArray read(qint64 ) //读取 qint64大的数据 并返回
QByteArray readAll() //读取所有数据
练习:实现客户端与调试助手的双向通信
①、服务端:Server.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//1、创建一个服务器对象
server = new QTcpServer(this);
//2、开始监听
if(server->listen(QHostAddress :: Any, 7777))
{
qDebug() << "监听成功" << endl;
}
else
{
qDebug() << "监听失败" << endl;
}
//3、关联新的链接信号
connect(server, SIGNAL(newConnection()), this, SLOT(accept_connect()));
}
MainWindow::~MainWindow()
{
delete ui;
}
int i=0;
QTcpSocket *new_socket ;
void MainWindow :: accept_connect()
{
qDebug() << "有新的链接请求处理" << endl;
//产生新的通信对象
new_socket = server->nextPendingConnection();
//哪里产生对象,就哪里关联
connect(new_socket, SIGNAL(readyRead()), this, SLOT(read_data()));
}
//收到信息读取
void MainWindow :: read_data()
{
QString msg = new_socket->readAll();
//取出发送者的IP地址
qDebug() << new_socket->peerAddress() << endl;
qDebug() << msg <<endl;
//显示收到信息
ui->textBrowser->setText(msg);
}
//发送信息给客户端
void MainWindow::on_pushButton_clicked()
{
QString msg = ui->textEdit->toPlainText();
new_socket->write(msg.toUtf8());
}
②、服务端:Client.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
QTcpSocket *socket;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//1、创建客户端通信对象
socket = new QTcpSocket(this);
//2、链接服务器
socket->connectToHost("192.168.124.54", 7777);
//3、数据的发送
socket->write("Hello ");
//4、关联刻度信号
connect(socket, SIGNAL(readyRead()), this, SLOT(read_date()));
}
MainWindow::~MainWindow()
{
delete ui;
}
//读取信息
void MainWindow::read_date()
{
QString msg = socket->readAll();
//显示收到信息
ui->textBrowser->setText(msg);
}
//发送信息
void MainWindow::on_pushButton_clicked()
{
QString msg = ui->textEdit->toPlainText();
socket->write(msg.toUtf8());
}
三、UDP通信
1、QUdpSocket Class类
Header: #include 头文件
qmake: QT += network 模块
Inherits: QAbstractSocket 父类
2、函数接口:
构造函数:
QUdpSocket(QObject *parent = nullptr)
发送数据的接口:
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address,quint16 port)
data:需要发送的数据
size:数据的大小
address:接收端的IP
port : 接收端的端口
qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port)
3、接收端:
1.绑定UDP socket
bool QAbstractSocket::bind(const QHostAddress &address, quint16 port = 0)
address:需要绑定的地址
port:需要绑定的端口
2.读取数据
qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address =nullptr, quint16 *port = nullptr)
data:读取后数据的存放地址
maxSize:读取的数据最大值
address:发送者的IP
port:发生者的端口
QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize = -1)
QNetworkDatagram 网络数据管理类
QHostAddress senderAddress() const //发送者的IP
int senderPort() const //发生者端口
int destinationPort() const 获取对方的端口
练习:
①、接收端:recv.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QNetworkDatagram>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//1、创建接收端
socket = new QUdpSocket(this);
//2、绑定
if(socket->bind(QHostAddress::Any, 7777))
{
qDebug() << "绑定成功" << endl;
}
else
{
qDebug() << "绑定失败" << endl;
}
//3、关联可读信号
connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::readData()
{
qDebug() << "读取数据" << endl;
//判断是否有网络数据
while (socket->hasPendingDatagrams())
{
//把所有的数据读取到msg
QNetworkDatagram msg = socket->receiveDatagram();
//输出IP和Port信息
qDebug() << msg.senderAddress().toString() << endl;
qDebug() << msg.senderPort() << endl;
//把发送端发送的数据转化为原来的QString类型数据
QString decodeMsg = QString :: fromUtf8(msg.data());
//输出数据
qDebug() << decodeMsg << endl;
}
}
②、发送端:send.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//1、创建发送端
socket = new QUdpSocket(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
//按键按下发送信息
void MainWindow::on_pushButton_clicked()
{
//获取对话框信息
QString msg = ui->lineEdit->text();
//利用套接字发送信息
socket->writeDatagram(ui->lineEdit->text().toUtf8(), QHostAddress("192.168.124.54"), 7777);
}
四、HTTP 请求
超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的信息以及得到什么样的响应
简单理解:客户通过http请求协议从服务器中获取需要的数据
免费API接口
http://api.qingyunke.com/ //机器人 api
舔狗API 官网
http://v2.alapi.cn
http://v2.alapi.cn/api/dog?
token=3ydsG67GrDABA97n(自己的token)
http://v2.alapi.cn/api/acg?
token=3ydsG67GrDABA97n(自己的token)
http://v2.alapi.cn/api/acg?
token=3ydsG67GrDABA97n(自己的token)
五、QT 中的HTTP 请求
1、QNetworkAccessManager Class网络请求管理器
Header: #include
qmake: QT += network
Since: Qt 4.4
Inherits: QObject
2、官方的请求 demo
//1.新建网络请求 管理器
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
//关联管理器的 finished 信号
connect(manager,&QNetworkAccessManager::finished,this, &MyClass::replyFinished);
//2.往http://qt-project.org 网站发起请求
manager->get(QNetworkRequest(QUrl("http://qtproject.org")));
网络请求信号:
void finished(QNetworkReply *reply)
3、QNetworkReply Class 网络请求数据管理器
Header: #include
qmake: QT += network
Since: Qt 4.4
Inherits: QIODevice
4、函数接口
//读取所有网络返回的数据
readAll()
//信号
void downloadProgress(qint64 bytesReceived,
qint64 bytesTotal) 下载进度信号
void finished() 下载完毕信号
void readyRead() 有数据可读信号
练习:获取舔狗API的数据
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
//添加网络请求管理器
#include <QNetworkAccessManager>
#include <QLabel>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//1、新建网络请求管理器
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
//2、关联管理器的finished信号
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
//3、往http://qt-project.org 网站发起请求
manager->get(QNetworkRequest(QUrl("http://v2.alapi.cn/api/dog?token=1tXlTpqdAcx4jXVm")));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::replyFinished(QNetworkReply *reply)
{
//读取所有的网络数据
QString msg = reply->readAll();
ui->textBrowser->setText(msg);
}
- 注意:假如QT不能使用https,可以把https改为http