qt网络编程
2021/7/14 20:06:11
本文主要是介绍qt网络编程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录
网络编程
Socket
qt下的socket
qt的TCP连接过程
TCP服务端给客户端传文件举例:
qt的UDP
qt的UDP单播举例:
UDP的广播与组播(多播)
网络编程
三个要素:IP地址、端口号和通信协议
IP地址:网络中的计算机使用IP地址来进行唯一标识,IP地址有IPv4和IPv6两种类型。IPv4采用十进制或二进制表示形式,十进制是一种比较常用的表示形式,如192.158.147.3。IPv6采用十六进制表示形式
端口号:计算机中的应用程序的一个整数数字标号,用来区分不同的应用程序
0 ~ 1024 为被系统使用或保留的端口号,0 ~ 65535为有效的端口号,也就是说我们要对一些程序定义端口号的时候,要选择1024 ~ 65535范围内的整数数字。
MySQL的端口号是3306,SQLServer的端口号是1433,Oracle的端口号是1521。
通信协议就是网络通信中的规则,分为TCP协议(面向连接的)和UDP协议(面向传输数据)两种
Socket
又叫“套接字”,它是计算机之间进行通信的一种约定或一种方式
通过 socket 这种约定,计算机可以接受其他计算机的数据,或者向其他计算机发送数据,里面有很多特殊的函数,是对其他计算机文件的读写操作
“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。
即socket是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
Socket()函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。
qt下的socket
TCP一般发文件,音频等,UDP一般发文字
QT += network
LINUX下的TCP:
在LINUX下进行网络编程,我们可以使用LINUX提供的统一的套接字接口。但是这种方法牵涉到太多的结构体,比如IP地址,端口转换等。QT中提供的SOCKET完全使用了类的封装机制,使用户不需要接触底层的各种结构体操作。而且它采用QT本身的信号和槽机制,使编写的程序更容易理解。
qt的TCP连接过程
不管谁发送信息,成功后,对方的通信套接字触发readyRead()
TCP服务端给客户端传文件举例:
传文件流程图
server ui 如下:
public: void sendData();//发数据 private: QTcpServer *tcpServer;//监听套接字 QTcpSocket *tcpSocket;//通信套接字 QFile file;//文件对象 QString filename; qint64 fileSize; qint64 sendSize;//已经发送文件的大小 QTimer timer;//定时器
构造函数中
tcpServer =new QTcpServer(this); tcpServer->listen(QHostAddress::Any,8888);//监听所有网址,设置server的端口8888 //连接成功自动触发newConnection connect(tcpServer,&QTcpServer::newConnection, [=]() { tcpSocket =tcpServer->nextPendingConnection();//获取连接进来的socket QString ip=tcpSocket->peerAddress().toString(); qint16 port =tcpSocket->peerPort(); QString temp =QString("[%1:%2]:zhaoyi成功连接").arg(ip).arg(port); ui->textEditread->setText(temp); //显示对方的ip和端口 } ); //关闭定时器,发数据 connect(&timer,&QTimer::timeout, [=]() { timer.stop(); sendData(); } ); }
//选文件 void server::on_pushButtonxuanwj_clicked() { QString filepath=QFileDialog::getOpenFileName(this,"open","../"); if(filepath.isEmpty()==false)//如果选择路径有效 { //初始化 filename.clear(); fileSize=0; //获取文件信息 QFileInfo info(filepath); filename=info.fileName(); fileSize=info.size(); sendSize=0;//发送文件的大小 file.setFileName(filepath);//指定文件名 bool isok=file.open(QIODevice::ReadOnly);//只读打开 if(isok==false) { qDebug()<<"只读失败"; } ui->textEdit->append(filepath);//提示文件路径 } else { qDebug()<<"读文件失败"; } }
//发文件 void server::on_pushButtonxuan_clicked() { //先发文件头信息 文件名##文件大小 QString head=QString("%1##%2").arg(filename).arg(fileSize); qint64 len=tcpSocket->write(head.toUtf8()); if(len>0)//如果头文件信息发送成功 { timer.start(100);//间隔一定时间,发真正的文件,防止TCP黏包 } else { qDebug()<<"head发送失败"; file.close(); } }
void server::sendData() { qint64 len=0; do { char buf[4*1024]={0};//发的大小 len=0; //读多少,发多少 len=file.read(buf,sizeof(buf)); len=tcpSocket->write(buf,len); sendSize+=len;//累计 }while(len>0);//判断读完 if(sendSize == fileSize) { ui->textEdit->append("文件发送完毕"); file.close(); tcpSocket->disconnectFromHost(); tcpSocket->close(); } }
client ui 如下:
private: QTcpSocket *tcpSocket; QFile file;//文件对象 QString filename; qint64 fileSize; qint64 recvSize;//已经接受文件的大小 bool isStart;
tcpSocket=new QTcpSocket(this); isStart=true; recvSize=0; connect(tcpSocket,&QTcpSocket::readyRead, [=]() { QByteArray buf=tcpSocket->readAll();//取出所有内容 if(isStart==true) { isStart=false; //解析头文件信息 /*section的功能就是从一段字符串中拿出某一段连续的部分 从位置标识开始从左到右:0,1,2,3,4,5... */ filename=QString(buf).section("##",0,0); fileSize=QString(buf).section("##",1,1).toInt();//QString->int //打开文件 file.setFileName(filename); bool isok=file.open(QIODevice::WriteOnly); if(isok==false) { qDebug()<<"写入错误"; } } else//发真正的文件数据 { qint64 len=file.write(buf);//写入数据 recvSize+=len; if(recvSize==fileSize) { file.close(); QMessageBox::information(this,"ok","写入ok"); tcpSocket->disconnectFromHost(); tcpSocket->close(); } } } );
//连接 void client::on_pushButtonlianjie_clicked() { QString ip=ui->lineEditIP->text(); qint16 port=ui->lineEditport->text().toInt(); tcpSocket->connectToHost(QHostAddress(ip),port); }
LINUX下的UDP
qt的UDP
qt的UDP单播举例:
只发送到另一个指定地址和端口的UDP客户端,是一对一的数据传输
.cpp
udpSocket =new QUdpSocket(this); udpSocket->bind(8888); setWindowTitle("8888");//标题 connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);//自定义槽函数 //接受对方的发来数据 void Widget::dealMsg() { char buf[1024]={0}; QHostAddress cliAddr; quint16 port; //对方连接“我”,“我”显示对方的ip,端口号和发来的数据 qint64 len= udpSocket->readDatagram(buf,sizeof(buf),&cliAddr,&port); if(len>0) { QString str =QString("[%1:%2] %3").arg(cliAddr.toString()).arg(port).arg(buf); ui->textEdit->setText(str); } }
//send控件 void Widget::on_Buttonsend_clicked() { //使用UDP协议进行信息的传输之前不需要建立连接,只需要给出对方的ip地址和端口号 QString ip =ui->lineEditip->text(); qint16 port =ui->lineEditport->text().toInt(); QString str =ui->textEdit->toPlainText(); udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port); }
UDP的广播与组播(多播)
TCP只有点对点,UDP才有点对点、组播、广播的概念
使用UDP协议进行信息的传输之前不需要建立连接。换句话说就是客户端向服务器发送信息,客户端只需要给出服务器的ip地址和端口号,然后将信息封装到一个待发送的报文中并且发送出去。至于服务器端是否存在,或者能否收到该报文,客户端根本不用管。
对于广播,同一网络范围内其他所有的UDP客户端都可以收到。单播和广播的实现方式基本相同,只是数据报的目标IP地址设置不同,在广播消息时,只需要将目标地址更换为一个特殊地址,即广播地址QHostAddress::Broadcast,一般为255.255.255.255
对于组播,组内成员(组播IP地址指定的多播组)都可以接收到。使用组播地址,其他的端口绑定、数据报收发功能与单播UDP完全相同。
组播(一对一组):
当多个客户端加入由一个组播地址定义的多播组之后,客户端向组播地址和端口发送数据报,组内成员都可以接收到
224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其他地址供路由协议使用
224.0.1.0~224.0.1.255是公用组播地址,可以用于internet
224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效
239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效
这篇关于qt网络编程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南