[QT] TCP协议演示

本文介绍了一个简单的文件传输程序,包括发送方和接收方的实现。发送方使用QTcpSocket进行TCP连接,并通过进度条显示文件传输状态;接收方使用QTcpServer监听连接请求,并通过UDP接收数据。文章详细展示了如何构建此类程序,包括文件读取、数据发送和接收等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个 文件传说 的东西...

先看 发送 的..

头文件

header.h

  1. #ifndefHEADER_H
  2. #defineHEADER_H
  3. #include<QDialog>
  4. #include<QTcpSocket>
  5. #include<QAbstractSocket>
  6. class QTcpSocket;
  7. class QDialogButtonBox;
  8. class QDialog;
  9. class QFile;
  10. class QProgressBar;
  11. class QLabel;
  12. class QVBoxLayout;
  13. class QTimer;
  14. class Dialog: public QDialog{
  15. Q_OBJECT
  16. public :
  17. Dialog(QWidget*parent=0);
  18. public slots:
  19. void start();
  20. void quit();
  21. void startTransfer();
  22. void updateClientProgress(qint64numBytes);
  23. void displayError(QAbstractSocket::SocketErrorsocketError);
  24. void openFile();
  25. void connectError();
  26. private :
  27. QProgressBar*clientProgressBar;
  28. QLabel*clientStatusLabel;
  29. QPushButton*startButton;
  30. QPushButton*quitButton;
  31. QPushButton*openButton;
  32. QDialogButtonBox*buttonBox;
  33. QVBoxLayout*mainLayout;
  34. QTcpSockettcpClient;
  35. int flag;
  36. qint64TotalBytes;
  37. qint64bytesWritten;
  38. qint64bytesToWrite;
  39. qint64localSize;
  40. QTimer*timer;
  41. QStringfileName;
  42. QFile*localFile;
  43. QByteArrayoutBlock;
  44. };
  45. #endif//HEADER_H

#ifndef HEADER_H #define HEADER_H #include <QDialog> #include <QTcpSocket> #include <QAbstractSocket> class QTcpSocket; class QDialogButtonBox; class QDialog; class QFile; class QProgressBar; class QLabel; class QVBoxLayout; class QTimer; class Dialog:public QDialog{ Q_OBJECT public: Dialog(QWidget *parent=0); public slots: void start(); void quit(); void startTransfer(); void updateClientProgress(qint64 numBytes); void displayError(QAbstractSocket::SocketError socketError); void openFile(); void connectError(); private : QProgressBar *clientProgressBar; QLabel *clientStatusLabel; QPushButton *startButton; QPushButton *quitButton; QPushButton *openButton; QDialogButtonBox *buttonBox; QVBoxLayout *mainLayout; QTcpSocket tcpClient; int flag; qint64 TotalBytes; qint64 bytesWritten; qint64 bytesToWrite; qint64 localSize; QTimer *timer; QString fileName; QFile *localFile; QByteArray outBlock; }; #endif // HEADER_H

main.cpp

  1. #include<QtGui>
  2. #include<QHostAddress>
  3. #include"header.h"
  4. //构造函数一些初始化操作
  5. Dialog::Dialog(QWidget*parent):QDialog(parent){
  6. localSize=4*1024;
  7. TotalBytes=0;
  8. bytesWritten=0;
  9. bytesToWrite=0;
  10. setWindowTitle(tr("发送文件" ));
  11. clientProgressBar=new QProgressBar;
  12. clientStatusLabel=new QLabel(tr( "客户端准备完毕" ));
  13. startButton=new QPushButton(tr( "开始" ));
  14. quitButton=new QPushButton(tr( "退出" ));
  15. openButton=new QPushButton(tr( "打开" ));
  16. startButton->setEnabled(false );
  17. buttonBox=new QDialogButtonBox;
  18. buttonBox->addButton(startButton,QDialogButtonBox::ActionRole);
  19. buttonBox->addButton(openButton,QDialogButtonBox::ActionRole);
  20. buttonBox->addButton(quitButton,QDialogButtonBox::RejectRole);
  21. mainLayout=new QVBoxLayout;
  22. mainLayout->addWidget(clientProgressBar);
  23. mainLayout->addWidget(clientStatusLabel);
  24. mainLayout->addWidget(buttonBox);
  25. setLayout(mainLayout);
  26. connect(startButton,SIGNAL(clicked()),this ,SLOT(start()));
  27. connect(openButton,SIGNAL(clicked()),this ,SLOT(openFile()));
  28. connect(quitButton,SIGNAL(clicked()),this ,SLOT(quit()));
  29. timer=new QTimer( this );
  30. //connect(timer,SIGNAL(timeout()),this,SLOT(connectError()));
  31. connect(&tcpClient,SIGNAL(connected()),this ,SLOT(startTransfer()));
  32. connect(&tcpClient,SIGNAL(bytesWritten(qint64)),this ,SLOT(updateClientProgress(qint64)));
  33. connect(&tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this ,SLOT(displayError(QAbstractSocket::SocketError)));
  34. flag=1;
  35. }
  36. //连接超时错误
  37. void Dialog::connectError(){
  38. }
  39. //退出
  40. void Dialog::quit(){
  41. qApp->quit();
  42. }
  43. //开始连接服务器
  44. void Dialog::start(){
  45. timer->start(1000);
  46. startButton->setEnabled(false );
  47. QApplication::setOverrideCursor(Qt::WaitCursor);
  48. bytesWritten=0;
  49. clientStatusLabel->setText(tr("连接中" ));
  50. tcpClient.connectToHost(QHostAddress::LocalHost,8888);
  51. }
  52. //打开文件
  53. void Dialog::openFile(){
  54. fileName=QFileDialog::getOpenFileName(this );
  55. if (!fileName.isEmpty()){
  56. startButton->setEnabled(true );
  57. }
  58. }
  59. void Dialog::startTransfer(){
  60. //只读方式打开文件
  61. localFile=new QFile(fileName);
  62. if (!localFile->open(QFile::ReadOnly)){
  63. QMessageBox::warning(this ,tr( "应用程序" ),tr( "无法读取文件" ).arg(fileName).arg(localFile->errorString()));
  64. return ;
  65. }
  66. //获取文件大小
  67. TotalBytes=localFile->size();
  68. //发送缓冲区outBlock封装在一个QDataStream类型变量中
  69. QDataStreamsendOut(&outBlock,QIODevice::WriteOnly);
  70. //设置流化数据版本
  71. sendOut.setVersion(QDataStream::Qt_4_6);
  72. //通过.right去掉文件的路径部分,
  73. //fileName.lastIndexOf('/')返回的是文件最后一个/所在的位数(INT)
  74. //fileName.right()返回的是从右面开始数的位数的值.
  75. //例如路径如果是D:\MyDocuments\Tcp\header.h
  76. //fileName.lastIndexOf('/')返回的是从D开始到最后一个\的位数
  77. //fileName.right(8)意思就是从路径右面开始到第八位数的字符串
  78. QStringcurrentFile=fileName.right(fileName.size()-fileName.lastIndexOf('/' )-1);
  79. //构造一个临时文件头将总长度和文件名长度暂时为0
  80. sendOut<<qint64(0)<<qint64(0)<<currentFile;
  81. //获得文件头的实际存储大小追加到TotalBytes;
  82. TotalBytes+=outBlock.size();
  83. //将读写操作指向文件头.
  84. sendOut.device()->seek(0);
  85. //填写实际总长度和文件长度
  86. sendOut<<TotalBytes<<qint64((outBlock.size()-sizeof (qint64)*2));
  87. //调用write函数将文件头发出同时修改bytesToWrite;
  88. bytesToWrite=TotalBytes-tcpClient.write(outBlock);
  89. clientStatusLabel->setText(tr("已经连接" ));
  90. qDebug()<<currentFile<<TotalBytes;
  91. //清空缓冲区
  92. outBlock.resize(0);
  93. }
  94. //数据发出将会产生bytesWritten()信号然后调用此方法参数表示实际已发出的字节
  95. void Dialog::updateClientProgress(qint64numBytes){
  96. bytesWritten+=(int )numBytes;
  97. if (bytesToWrite>0){
  98. outBlock=localFile->read(qMin(bytesToWrite,localSize));
  99. bytesToWrite-=(int )tcpClient.write(outBlock);
  100. outBlock.resize(0);
  101. }else {
  102. localFile->close();
  103. }
  104. clientProgressBar->setMaximum(TotalBytes);
  105. clientProgressBar->setValue(bytesWritten);
  106. clientStatusLabel->setText(tr("已发送%1M" ).arg(bytesWritten/(1024*1024)));
  107. }
  108. //链接错误方法
  109. void Dialog::displayError(QAbstractSocket::SocketErrorsocketError){
  110. if (socketError=QTcpSocket::RemoteHostClosedError)
  111. return ;
  112. QMessageBox::information(this ,tr( "网络" ),tr( "产生如下错误:%1." ).arg(tcpClient.errorString()));
  113. tcpClient.close();
  114. clientProgressBar->reset();
  115. clientStatusLabel->setText(tr("客户端就绪" ));
  116. startButton->setEnabled(true );
  117. QApplication::restoreOverrideCursor();
  118. }
  119. int main( int argc, char **argv){
  120. QApplicationapp(argc,argv);
  121. QTextCodec::setCodecForTr(QTextCodec::codecForName("gb2312" ));
  122. Dialogdialog;
  123. dialog.show();
  124. return app.exec();
  125. }

#include <QtGui> #include <QHostAddress> #include "header.h" //构造函数 一些初始化操作 Dialog::Dialog(QWidget *parent):QDialog(parent){ localSize=4*1024; TotalBytes=0; bytesWritten=0; bytesToWrite=0; setWindowTitle(tr("发送文件")); clientProgressBar=new QProgressBar; clientStatusLabel=new QLabel(tr("客户端准备完毕")); startButton=new QPushButton(tr("开始")); quitButton=new QPushButton(tr("退出")); openButton=new QPushButton(tr("打开")); startButton->setEnabled(false); buttonBox=new QDialogButtonBox; buttonBox->addButton(startButton,QDialogButtonBox::ActionRole); buttonBox->addButton(openButton,QDialogButtonBox::ActionRole); buttonBox->addButton(quitButton,QDialogButtonBox::RejectRole); mainLayout=new QVBoxLayout; mainLayout->addWidget(clientProgressBar); mainLayout->addWidget(clientStatusLabel); mainLayout->addWidget(buttonBox); setLayout(mainLayout); connect(startButton,SIGNAL(clicked()),this,SLOT(start())); connect(openButton,SIGNAL(clicked()),this,SLOT(openFile())); connect(quitButton,SIGNAL(clicked()),this,SLOT(quit())); timer=new QTimer(this); // connect(timer,SIGNAL(timeout()),this,SLOT(connectError())); connect(&tcpClient,SIGNAL(connected()),this,SLOT(startTransfer())); connect(&tcpClient,SIGNAL(bytesWritten(qint64)),this,SLOT(updateClientProgress(qint64))); connect(&tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError))); flag=1; } //连接超时错误 void Dialog::connectError(){ } //退出 void Dialog::quit(){ qApp->quit(); } //开始连接服务器 void Dialog::start(){ timer->start(1000); startButton->setEnabled(false); QApplication::setOverrideCursor(Qt::WaitCursor); bytesWritten=0; clientStatusLabel->setText(tr("连接中")); tcpClient.connectToHost(QHostAddress::LocalHost,8888); } //打开文件 void Dialog::openFile(){ fileName=QFileDialog::getOpenFileName(this); if(!fileName.isEmpty()){ startButton->setEnabled(true); } } void Dialog::startTransfer(){ //只读方式打开文件 localFile=new QFile(fileName); if(!localFile->open(QFile::ReadOnly)){ QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件").arg(fileName).arg(localFile->errorString())); return ; } //获取 文件大小 TotalBytes=localFile->size(); //发送缓冲区outBlock封装在一个QDataStream类型变量中 QDataStream sendOut(&outBlock,QIODevice::WriteOnly); //设置流化数据版本 sendOut.setVersion(QDataStream::Qt_4_6); //通过.right去掉 文件的路径部分, //fileName.lastIndexOf('/')返回的是 文件最后一个 / 所在的位数(INT) //fileName.right()返回的是 从右面开始数 的位数的值. //例如 路径如果是D:\My Documents\Tcp\header.h //fileName.lastIndexOf('/')返回的是从D开始 到最后一个 \ 的位数 //fileName.right(8) 意思就是 从路径右面开始 到第八位数的字符串 QString currentFile=fileName.right(fileName.size()-fileName.lastIndexOf('/')-1); //构造一个临时文件头 将总长度和文件名长度暂时为0 sendOut<<qint64(0)<<qint64(0)<<currentFile; //获得文件头的实际存储大小 追加到 TotalBytes; TotalBytes+=outBlock.size(); //将读写操作指向文件头. sendOut.device()->seek(0); //填写实际总长度和文件长度 sendOut<<TotalBytes<<qint64((outBlock.size()-sizeof(qint64)*2)); //调用 write函数将文件头发出同时修改 bytesToWrite; bytesToWrite=TotalBytes-tcpClient.write(outBlock); clientStatusLabel->setText(tr("已经连接")); qDebug()<<currentFile<<TotalBytes; //清空缓冲区 outBlock.resize(0); } //数据发出 将会产生 bytesWritten()信号 然后调用此方法 参数表示实际已发出的字节 void Dialog::updateClientProgress(qint64 numBytes){ bytesWritten+=(int)numBytes; if(bytesToWrite>0){ outBlock=localFile->read(qMin(bytesToWrite,localSize)); bytesToWrite-=(int)tcpClient.write(outBlock); outBlock.resize(0); }else{ localFile->close(); } clientProgressBar->setMaximum(TotalBytes); clientProgressBar->setValue(bytesWritten); clientStatusLabel->setText(tr("已发送 %1 M").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(); } int main(int argc,char **argv){ QApplication app(argc,argv); QTextCodec::setCodecForTr( QTextCodec::codecForName("gb2312")); Dialog dialog; dialog.show(); return app.exec(); }

再看 接受文件

header.h

  1. #ifndefDIALOG_H
  2. #defineDIALOG_H
  3. #include<QDialog>
  4. #include<QTcpServer>
  5. class QFile;
  6. class QDialogButtonBox;
  7. class QLabel;
  8. class QProgressBar;
  9. class QPushButton;
  10. class QTcpSocket;
  11. class Dialog: public QDialog
  12. {
  13. Q_OBJECT
  14. public :
  15. Dialog(QWidget*parent=0);
  16. public slots:
  17. void start();
  18. void acceptConnection();
  19. void updateServerProgress();
  20. void displayError(QAbstractSocket::SocketErrorsocketError);
  21. private :
  22. QProgressBar*clientProgressBar;
  23. QProgressBar*serverProgressBar;
  24. QLabel*serverStatusLabel;
  25. QPushButton*startButton;
  26. QPushButton*quitButton;
  27. QPushButton*openButton;
  28. QDialogButtonBox*buttonBox;
  29. QTcpServertcpServer;
  30. QTcpSocket*tcpServerConnection;
  31. qint64TotalBytes;
  32. qint64bytesReceived;
  33. qint64fileNameSize;
  34. QStringfileName;
  35. QFile*localFile;
  36. QByteArrayinBlock;
  37. };
  38. #endif

#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QTcpServer> class QFile; class QDialogButtonBox; class QLabel; class QProgressBar; class QPushButton; class QTcpSocket; class Dialog : public QDialog { Q_OBJECT public: Dialog(QWidget *parent = 0); public slots: void start(); void acceptConnection(); void updateServerProgress(); void displayError(QAbstractSocket::SocketError socketError); private: QProgressBar *clientProgressBar; QProgressBar *serverProgressBar; QLabel *serverStatusLabel; QPushButton *startButton; QPushButton *quitButton; QPushButton *openButton; QDialogButtonBox *buttonBox; QTcpServer tcpServer; QTcpSocket *tcpServerConnection; qint64 TotalBytes; qint64 bytesReceived; qint64 fileNameSize; QString fileName; QFile *localFile; QByteArray inBlock; }; #endif

再看 实现文件

dialog.cpp

  1. #include"receiver.h"
  2. #include<QtNetwork>
  3. Receiver::Receiver(QObject*parent)
  4. :QObject(parent)
  5. {
  6. udpSocket=new QUdpSocket( this );
  7. udpSocket->bind(44444);
  8. connect(udpSocket,SIGNAL(readyRead()),
  9. this ,SLOT(processPendingDatagrams()));
  10. }
  11. void Receiver::processPendingDatagrams()
  12. {
  13. while (udpSocket->hasPendingDatagrams()){
  14. QByteArraydatagram;
  15. datagram.resize(udpSocket->pendingDatagramSize());
  16. udpSocket->readDatagram(datagram.data(),datagram.size());
  17. qDebug()<<(tr("接收数据:\"%1\"" )
  18. .arg(datagram.data()));
  19. }
  20. }

#include "receiver.h" #include <QtNetwork> Receiver::Receiver(QObject *parent) : QObject(parent) { udpSocket = new QUdpSocket(this); udpSocket->bind(44444); connect(udpSocket, SIGNAL(readyRead()), this, SLOT(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.cpp

  1. #include<QApplication>
  2. #include<QtCore>
  3. #include"dialog.h"
  4. int main( int argc, char *argv[])
  5. {
  6. QApplicationapp(argc,argv);
  7. QTextCodec::setCodecForTr(QTextCodec::codecForName("gb2312" ));
  8. Dialogdialog;
  9. dialog.show();
  10. return dialog.exec();
  11. }

#include <QApplication> #include <QtCore> #include "dialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QTextCodec::setCodecForTr( QTextCodec::codecForName("gb2312")); Dialog dialog; dialog.show(); return dialog.exec(); }

执行结果如下..

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值