void Server::sndMsg() { ui->sSendBtn->setEnabled(false); clntConn = tSrv->nextPendingConnection(); connect(clntConn, SIGNAL(bytesWritten(qint64)), this, SLOT (updClntProgress(qint64))); ui->sStatusLbl->setText(tr("开始传输文件 %1 !").arg(theFileName)); locFile = new QFile(fileName); //只读方式打开 if(!locFile->open((QFile::ReadOnly))){ QMessageBox::warning(this, tr(" 应 用 程 序 "), tr(" 无 法 读 取 文 件 %1:\n%2").arg(fileName).arg(locFile->errorString())); return; } //获取待发送文件的大小 totalBytes = locFile->size(); //将发送缓冲区outBlock封装在一个QDataStream类型的变量中,这样做可以很方便通过重载"<<"操作符填写文件头结构 QDataStream sendOut(&outBlock, QIODevice::WriteOnly); sendOut.setVersion(QDataStream::Qt_4_7); time.start(); //开始计时--用来统计传输所用的时间 QString curFile = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);//去掉文件的路径部分 sendOut << qint64(0) << qint64(0) << curFile;//构造一个临时的头文件,将该值追加到totalBytes字段,从而完成实际需发送字节数的记录 totalBytes += outBlock.size(); sendOut.device()->seek(0);//将读写操作指向从头开始 sendOut << totalBytes << qint64((outBlock.size() - sizeof(qint64)*2));//填写实际的总长度和文件长度 bytesTobeWrite = totalBytes - clntConn->write(outBlock);//将改文件头发出,同时修改待发送字节数bytesTobeWrite outBlock.resize(0); //清空发送缓冲区以备下次使用 }
时间: 2024-04-02 09:32:15 浏览: 72
这段代码是一个 Qt 程序中的一个服务器类的槽函数,用于处理发送文件的请求。
在函数中,首先禁用了发送按钮,然后通过 `nextPendingConnection()` 函数获取一个新的客户端连接,即要接收文件的客户端。接着,连接了客户端连接的 `bytesWritten()` 信号,并将其与 `updClntProgress()` 槽函数连接起来,用于更新客户端的传输进度。
接下来,打开待发送的文件,并获取其大小。然后,将发送缓冲区 `outBlock` 封装在一个 `QDataStream` 类型的变量 `sendOut` 中,并设置其版本为 `Qt_4_7`。接着,通过 `sendOut` 向缓冲区写入一个临时的头文件,用于记录实际需发送字节数。然后,将 `sendOut` 的读写操作指向从头开始,并将实际的总长度和文件长度填写到头文件中。最后,将头文件发出,并修改待发送字节数 `bytesTobeWrite`。发送缓冲区 `outBlock` 则被清空以备下次使用。
相关问题
erver::Server(QWidget *parent) : QDialog(parent), ui(new Ui::Server) { ui->setupUi(this); setFixedSize(400, 207); tPort = 5555; tSrv = new QTcpServer(this); connect(tSrv, SIGNAL(newConnection()), this, SLOT(sndMsg())); initSrv(); } Server::~Server() { delete ui; } void Server::initSrv() { payloadSize = 64*1024; totalBytes = 0; bytesWritten = 0; bytesTobeWrite = 0; ui->sStatusLbl->setText(tr("请选择要传送的文件")); ui->progressBar->reset(); ui->sOpenBtn->setEnabled(true); ui->sSendBtn->setEnabled(false); tSrv->close(); } void Server::refused() { tSrv->close(); ui->sStatusLbl->setText(tr("对方拒绝接受!")); } void Server::closeEvent(QCloseEvent *) { on_sCloseBtn_clicked(); }
这段代码实现了一个QTcpServer的初始化和一些槽函数的定义。下面是对每个函数的解释:
1. `Server::Server(QWidget *parent) : QDialog(parent), ui(new Ui::Server)`
构造函数,初始化了QTcpServer和UI界面。
2. `void Server::initSrv()`
初始化函数,用于初始化各个变量和控件的状态。
3. `void Server::refused()`
当连接被拒绝时的槽函数,关闭QTcpServer并更新状态栏。
4. `void Server::closeEvent(QCloseEvent *)`
重载关闭事件,关闭QTcpServer。
5. `void Server::~Server()`
析构函数,释放内存。
6. `void Server::sndMsg()`
当有新的连接时的槽函数,用于发送文件数据。
7. `void Server::on_sCloseBtn_clicked()`
关闭按钮的槽函数,关闭QTcpServer并更新状态栏。
8. `void Server::on_sOpenBtn_clicked()`
打开按钮的槽函数,用于选择要传送的文件。
9. `void Server::on_sSendBtn_clicked()`
发送按钮的槽函数,用于发送文件数据。
10. `void Server::updateClientProgress(qint64 numBytes)`
更新客户端进度条的槽函数,用于更新状态栏和进度条。
11. `void Server::displayError(QAbstractSocket::SocketError)`
显示错误信息的槽函数,用于更新状态栏。
Widget::Widget(QWidget *parent, QString usrname) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); uName = usrname; udpSocket = new QUdpSocket(this); port = 23232; udpSocket->bind(port, QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint); connect(udpSocket,SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));//随时接收来自其他用户的UDP广播消息 sndMsg(UsrEnter); srv = new Server(this); connect(srv, SIGNAL(sndFileName(QString)), this, SLOT(getFileName(QString))); } Widget::~Widget() { delete ui; } //处理新用户加入 void Widget::usrEnter(QString usrname, QString ipaddr) { bool isEmpty = ui->usrTblWidget->findItems(usrname, Qt::MatchExactly).isEmpty(); if (isEmpty) { QTableWidgetItem *usr = new QTableWidgetItem(usrname); QTableWidgetItem *ip = new QTableWidgetItem(ipaddr); ui->usrTblWidget->insertRow(0); ui->usrTblWidget->setItem(0, 0, usr); ui->usrTblWidget->setItem(0, 1, ip); ui->msgBrowser->setTextColor(Qt::gray); ui->msgBrowser->setCurrentFont(QFont("Times New Roman", 10)); ui->msgBrowser->append(tr("%1 在线!").arg(usrname)); ui->usrNumLbl->setText(tr("在线人数: 1%").arg(ui->usrTblWidget->rowCount())); sndMsg(UsrEnter);//在线的各个端口也要告诉新加入的断点它们自己的用户信息 } } void Widget::usrLeft(QString usrname, QString time) { int rowNum = ui->usrTblWidget->findItems(usrname, Qt::MatchExactly).first()->row(); ui->usrTblWidget->removeRow(rowNum); ui->msgBrowser->setTextColor(Qt::gray); ui->msgBrowser->setCurrentFont(QFont("Times New Roman", 10)); ui->msgBrowser->append(tr("%1 于 %2 离开!").arg(usrname).arg(time)); ui->usrNumLbl->setText(tr(" 在 线 人 数 : %1").arg(ui->usrTblWidget->rowCount())); }
这段代码是一个Qt的Widget类的成员函数,主要实现了处理新用户加入和用户离开的功能。具体来说,当一个新用户加入聊天室时,会在聊天室的用户列表中添加该用户的用户名和IP地址,并向聊天室中的其他用户发送UDP广播消息通知他们有新用户加入了聊天室。当一个用户离开聊天室时,会从用户列表中移除该用户的信息,并向聊天室中的其他用户发送UDP广播消息通知他们该用户已经离开聊天室。
在代码中,变量uName表示当前用户的用户名,udpSocket表示用于接收UDP广播消息的套接字,srv表示用于处理文件传输的服务器对象。在构造函数中,首先绑定了UDP套接字,并且连接了readyRead()信号与processPendingDatagrams()槽,以便随时接收来自其他用户的UDP广播消息。然后调用了sndMsg函数向聊天室中的其他用户发送UDP广播消息,表示当前用户已经加入聊天室。最后创建了一个服务器对象,连接了其sndFileName信号与getFileName槽,以便在文件传输时获取文件名。
在usrEnter函数中,首先判断该用户是否已经在用户列表中,如果不在,则创建一个新的用户表项,并在用户列表中插入该项。然后向聊天室中的其他用户发送UDP广播消息,通知他们有新用户加入了聊天室。最后将在线人数显示在用户界面上。
在usrLeft函数中,首先找到该用户在用户列表中的行数,并从用户列表中移除该用户的信息。然后向聊天室中的其他用户发送UDP广播消息,通知他们该用户已经离开聊天室。最后将在线人数显示在用户界面上。
阅读全文