Qt:网络编程
来源:互联网 发布:js上下移动div 编辑:程序博客网 时间:2024/06/05 20:27
一、UDP应用(QUdpSocket)
服务器:
1、初始化套接字
2、绑定
3、接收/发送
4、关闭套接字
客户端:
1、初始化套接字
2、发送/接收
3、关闭套接字
Qt提供了QUdpSocket类用于编写UDP程序,QUdpSocket类提供的另一个重要功能是广播
eg:
客户端://客户端仅广播,服务器端仅接收
class Sender : public QObject{
Q_OBJECT
public:
Sender(QObject *parent = 0);
~Sender();
void start();
private slots:
void broadcastDatagram();
private:
QUdpSocket *udpSocket;
QTimer *timer;
int messageNo;
};
Sender::Sender(QObject *parent) : QObject(parent){
timer = new QTimer(this);
udpSocket = new QUdpSocket(this); //创建套接字
connect(timer,SIGNAL(timeout()),this,SLOT(broadcastDatagram()));
messageNo = 1;
}
void Sender::start(){
timer->start(1000);
}
void Sender::broadcastDatagram(){
qDebug() << (tr("开始广播:%1").arg(messageNo));
QByteArray datagram = "BroadCast Message: " + QByteArray::number(messageNo);
udpSocket->writeDatagram(datagram.data(),datagram.size(),
QHostAddress::Broadcast,44444);//发送
++messageNo;
}
//QHostAddress::Broadcast对应IPv4下的广播地址.QHostAddress::LocalHost(端到端)
int main(int argc,char *argv[]){
QCoreApplication app(argc,argv);
Sender sender;
sender.start();
return app.exec();
}
//////////////////////////////////////////////////////////////////////////////////
服务器端:
class Receiver : public QObject{
Q_OBJECT
public:
Receiver(QObject *parent = 0);
~Recvier();
private slots:
void processPendingDatagrams();
private:
QUdpSocket *udpSocket;
};
Receiver::Receiver(QObject *parent) : QObject(parent){
udpSocket = new QUdpSocket(this); //创建套接字
udpSocket->bind(44444); //绑定
connect(udpSocket,SIGNAL(readyRead()),
this,SLOG(processPendingDatagrams()));
}
void Receiver::processPendingDatagrams(){
while(udpSocket->hasPendingDatagrams){
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(),datagram.size()); //接收
qDebug() << (tr("接收数据:\"%1\"")
.arg(datagram.data()));
}
}
//main函数与客户端类似
实际应用中,客户端和服务器双方均需要进行数据的收发,即全双工工作方式,这时需分别使用QUdpSocket::bind()函数绑定
各自的主机和端口来读取数据,同时还可以在同一个套接字上使用QUdpSocket::writeDatagram()函数向不同的目的地和端口发送数据。
/*********************************************************************************************************************/
二、TCP应用(QTcpSocket,QTcpServer):
服务器端:
1、初始化套接字
2、绑定
3、监听
4、接受连接
5、接收/发送
6、关闭套接字
客户端:
1、初始化套接字
2、连接
3、发送/接收
4、关闭套接字
QTcpSocket类通过其父类QAbstractSocket继承了QIODevice类,因此可以使用QTextStream和QDataStream这样的流结构类。
QTcpServer类在服务器端处理外来的TCP客户端连接,该类直接继承于QObject基类。
eg:
客户端:
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
public slots:
void start();
void startTransfor();
void updateClientProgress(qint64 numBytes);
void displayError(QAbstractSocket::SocketError socketError);
void openFile();
private:
QProgressBar *clientProgressBar;
QLabel *clientStatusLabel;
QPushButton *startButton;
QPushButton *quitButton;
QPushButton *openButton;
QDialogButtonBox *buttonBox;
QTcpSocket tcpClient;
qint64 TotalBytes;
qint64 bytesWritten;
qint64 bytesToWrite;
qint64 loadSize;
QString fileName;
QFile *localFile;
QByteArray outBlock;
};
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
loadSize = 4 * 1024;
TotalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
clientProgressBar = new QProgressBar;
clientStatusLabel = new QLabel(tr("客户端就绪"));
startButton = new QPushButton(tr("开始"));
quitButton = new QPushButton(tr("退出"));
openButton = new QPushButton(tr("打开"));
startButton->setEnabled(false);
connect(startButton,SIGNAL(clicked()),this,SLOT(start()));
connect(quitButton,SIGNAL(clicked()),this,SLOT(close()));
connect(openButton,SIGNAL(clicked()),this,SLOT(openFile()));
connect(&tcpClient,SIGNAL(connected()),this,SLOT(startTransfor()));
connect(&tcpClient,SIGNAL(bytesWritten(qint64)),
this,SLOT(updateClientProgress(qint64)));
connect(&tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),
this,SLOT(displayError(QAbstractSocket::SocketError)));
//成功与服务器建立连接:connected()信号,数据发送成功:bytesWriten()信号,产生错误:error()信号
}
void Dialog::openFile(){
fileName = QFileDialog::getOpenFileName(this); //获取要传递的文件名
if(!fileName.isEmpty()){
startButton->setEnabled(true);
}
}
void Dialog::start(){
startButton->setEnabled(false);
QApplication::setOverrideCursor(Qt::WaitCursor);
bytesWritten = 0;
clientStatusLabel->setText(tr("连接中..."));
tcpClient.connectToHost(QHostAddress::LocalHost,16689); //连接服务器
}
void Dialog::startTransfor(){
localFile = new QFile(filName);
if(!localFile->open(QFile::ReadOnly)){
QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2")
.arg(fileName).arg(localFile->errorString()));
return ;
}
TotalBytes = localFile->size(); //文件大小
QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_5_3);
QString currentFile = fileName.right(fileName.size()
- fileName.lastIndexOf('/') - 1);
sendOut << qint64(0) << qint64(0) << currentFile; //先占个地儿
TotalBytes += outBlock.size(); //发送数据的总长度
sendOut.device()->seek(0);
sendOut << TotalBytes << qint64(outBlock.size() - sizeof(qint64)*2);
bytesToWrite = TotalBytes - tcpClient.write(outBlock); //发送数据
clientStatusLabel->setText(tr("已连接"));
qDebug() << currentFile << TotalBytes;
outBlock.resize(0);
}//发送文件数据格式:总长度(64位),文件名长度(64位),文件名,文件数据
void Dialog::updateClientProgress(qint64 numBytes){ //槽
bytesWritten += (int)numBytes; //已发送的字节数
if(bytesToWrite > 0){
outBlock = localFile->read(qMin(bytesToWrite,loadSize));//尽可能发送4k
bytesToWrite -= (int)tcpClient.write(outBlock);
outBlock.resize(0);
}else{
localFile->close();
}
clientProgressBar->setMaximum(TotalBytes);
clientProgressBar->setValue(bytesWritten);
clientStatusLabel->setText(tr("已发送 %1MB").arg(bytesWritten)/(1024*1024);
}
void Dialog::displayError(QAbstractSocket::SocketError socketError){ //槽
if(socketError == QTcpSocket::RemoteHostClosedError)
return ;
QMessageBox::information(this,tr("网络"),tr("产生错误:%1.")
.arg(tcpClient.errorString()));
tcpClient.close(); //出错,关闭套接字
clientProgressBar->reset();
clientStatusLabel->setText(tr("客户端就绪"));
startButton->setEnabled(true);
QApplication::restoreOverrideCursor();
}
//////////////////////////////////////////////////////////////////////////////////////////
服务器端:
#ifndef DIALOGSRV_H
#define DIALOGSRV_H
#include <QDialog>
class DialogSrv : public QDialog
{
Q_OBJECT
public:
explicit DialogSrv(QWidget *parent = 0);
signals:
public slots:
void start();
void acceptConnection();
void updateServerProgress();
void displayError(QAbstractSocket::SocketError);
private:
QProgressBar* clientProgressBar;
QProgressBar* serverProgressBar;
QLabel* serverStatusLabel;
QPushButton* startButton;
QPushButton* quitButton;
QPushButton* openButton;
QDialogButtonBox* buttonBox;
QTcpServer tcpServer;
QTcpSocket* tcpServerConnection;
qint64 TotalBytes;
qint64 bytesRecvived;
qint64 fileNameSize;
QString fileName;
QFile* localFile;
QByteArray inBlock;
};
#endif // DIALOGSRV_H
#include "dialogsrv.h"
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QProgressBar>
#include <QLabel>
#include <QPushButton>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFile>
#include <QByteArray>
#include <QString>
#include <QMessageBox>
DialogSrv::DialogSrv(QWidget *parent) :
QDialog(parent)
{
TotalBytes = 0;
bytesRecvived = 0;
fileNameSize = 0;
serverProgressBar = new QProgressBar;
serverStatusLabel = new QLabel(tr("服务端就绪"));
startButton = new QPushButton(tr("接收"));
quitButton = new QPushButton(tr("退出"));
connect(startButton,SIGNAL(clicked()),this,SLOT(start()));
connect(quitButton,SIGNAL(clicked()),this,SLOT(close()));
connect(&tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection()));
//有可用的Tcp连接时,QTcpServer发出newConnection()信号
}
DialogSrv::start(){
startButton->setEnabled(false);
QApplication::setOverrideCursor(Qt::WaitCursor);
bytesRecvived = 0;
while(!tcpServer.isListening() &&
!tcpServer.listen(QHostAddress::LocalHost,16689)){ //监听
QMessageBox::StandardButton ret =
QMessageBox::critical(this,
tr("回环"),
tr("无法开始测试:%1")
.arg(tcpServer.errorString()),
QMessageBox::Retry |
QMessageBox::Cancel);
if(ret = QMessageBox::Cancel)
return ;
}
serverStatusLabel->setText(tr("监听"));
}
void DialogSrv::acceptConnection(){
tcpServerConnection = tcpServer.nextPendingConnection();
connect(tcpServerConnection,SIGNAL(readyRead()),this,SLOT(updateServerProgress()));
connect(tcpServerConnection,SIGNAL(error(QAbstractSocket::SocketError)),
this,SLOT(displayError(QAbstractSocket::SocketError)));
serverStatusLabel->setText(tr("接受连接"));
tcpServer.close(); //只处理一个客户请求
}//当建立的连接有新的可供读取的数据时,QTcpSocket会发出readyRead()信号
void DialogSrv::updateServerProgress(){
QDataStream in(tcpServerConnection);
in.setVersion(QDataStream::Qt_5_3);
if(bytesRecvived <= sizeof(qint64)*2){ //文件头结构的接收分两步完成
if((tcpServerConnection->bytesAvailable() >= sizeof(qint64)*2)
&& (fileNameSize == 0)){
in >> TotalBytes >> fileNameSize; //接收总字节数,文件名大小
bytesRecvived += sizeof(qint64)*2;
}
if((tcpServerConnection->bytesAvailable() >= fileNameSize)
&& (fileNameSize != 0)){
in >> fileName; //接收文件名
bytesRecvived +=fileNameSize;
localFile = new QFile(fileName);
if(!localFile->open(QFile::WriteOnly)){
QMessageBox::warning(this,tr("应用程序"),
tr("无法读取文件%1:\n%2.")
.arg(fileName)
.arg(localFile->errorString()));
return ;
}
}else{
reutrn ;
}
}
if(bytesRecvived < TotalBytes){ //读取实际的文件数据
bytesRecvived += tcpServerConnection->bytesAvailable();
inBlock = tcpServerConnection->readAll(); //无格式的流,读到缓冲区中
localFile->write(inBlock);
inBlock.resize(0);
}
serverProgressBar->setMaximum(TotalBytes);
serverProgressBar->setValue(bytesRecvived);
qDebug() << bytesRecvived;
serverStatusLabel->setText(tr("已接收%1MB")
.arg(bytesRecvived/(1024*1024)));
if(bytesRecvived == TotalBytes){
tcpServerConnection->close(); //关闭连接
startButton->setEnabled(true);
QApplication::restoreOverrideCursor();
}
}
/*********************************************************************************************************************/
UDP和TCP编程总体上都是由信号槽组成并控制的,在实际项目中可灵活修改信号:
UDP客户端:时间到 -> 写数据报
UDP服务端:绑定;socket准备读 -> 当有等待的数据报时读数据报
TCP客户端:一点击开始 -> 连接主机(其中指定主机端口)
一点击打开 -> 打开文件
socket一连接上 -> 发送文件写数据
数据一发送成功 -> 更新(set)进度条
TCP服务端:一点击开始 -> 判断是否正在监听&&监听(其中指定主机端口)
当有新的连接 -> {准备读下一个等待的连接 -> 读,更新进度条
{错误处理
0 0
- QT:Qt 网络编程基础
- qt网络编程
- Qt网络编程之一
- Qt网络编程
- Qt网络编程
- QT网络编程实例
- QT网络编程-TCP
- QT网络编程-http
- QT网络编程-UDP
- Qt网络编程
- Qt网络编程之一
- qt网络编程
- 学习Qt网络编程
- Qt:网络编程
- Qt网络编程
- qt网络编程
- Qt 网络编程
- Qt网络编程
- sudo apt-get install -f失效
- unity3d NGUI中获取/判断鼠标(左右键等)的方法
- C++解析JSON jsoncpp库
- ubuntu 安装mac主题;亲测可用
- Android基础类之BaseAdapter
- Qt:网络编程
- 第19题 Remove Nth Node From End of List
- ID3DXEffect 和 fx文件
- 简易mp3播放器(SDL)
- Easyui datagrid editor为combobox时指定数据源
- 包含第三方jar包的mvn工程生成可执行jar包
- who is killer
- android背景颜色渐变
- Qt:文件处理