├── Client ├── Client.pro ├── Client.pro.autosave ├── Client.pro.user ├── debugonoroff.h ├── document.qrc ├── main.cpp ├── protocolcommand.h ├── widget.cpp ├── widget.h └── widget.ui ├── LICENSE ├── README.md └── Server ├── Server_V2.pro ├── Server_V2.pro.autosave ├── Server_V2.pro.user ├── clientaddress.cpp ├── clientaddress.h ├── debugonoroff.h ├── documents.qrc ├── img.qrc ├── img ├── child.png ├── loading4.gif └── teacher.png ├── main.cpp ├── myserver.cpp ├── myserver.h ├── mysocket.cpp ├── mysocket.h ├── mythread.cpp ├── mythread.h ├── protocolcommand.h ├── qnchatmessage.cpp ├── qnchatmessage.cpp.autosave ├── qnchatmessage.h ├── qnchatmessage.h.autosave ├── widget.cpp ├── widget.cpp.autosave ├── widget.h ├── widget.h.autosave └── widget.ui /Client/Client.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-08-01T11:57:10 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += network 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = Client 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | widget.cpp 17 | 18 | HEADERS += widget.h \ 19 | debugonoroff.h \ 20 | protocolcommand.h 21 | 22 | FORMS += widget.ui 23 | 24 | RESOURCES += \ 25 | document.qrc 26 | -------------------------------------------------------------------------------- /Client/Client.pro.autosave: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | QT += network 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | TARGET = Client 6 | TEMPLATE = app 7 | 8 | 9 | SOURCES += main.cpp\ 10 | widget.cpp 11 | 12 | HEADERS += widget.h \ 13 | debugonoroff.h \ 14 | protocolcommand.h 15 | 16 | FORMS += widget.ui 17 | 18 | RESOURCES += \ 19 | document.qrc 20 | -------------------------------------------------------------------------------- /Client/Client.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {801efd51-282a-4073-9e5f-4217bf3d15c6} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | true 60 | 61 | 62 | 63 | ProjectExplorer.Project.Target.0 64 | 65 | Desktop Qt 5.14.2 GCC 64bit 66 | Desktop Qt 5.14.2 GCC 64bit 67 | qt.qt5.5142.gcc_64_kit 68 | 0 69 | 0 70 | 0 71 | 72 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Debug 73 | 74 | 75 | true 76 | QtProjectManager.QMakeBuildStep 77 | true 78 | 79 | false 80 | false 81 | false 82 | 83 | 84 | true 85 | Qt4ProjectManager.MakeStep 86 | 87 | false 88 | 89 | 90 | false 91 | 92 | 2 93 | Build 94 | Build 95 | ProjectExplorer.BuildSteps.Build 96 | 97 | 98 | 99 | true 100 | Qt4ProjectManager.MakeStep 101 | 102 | true 103 | clean 104 | 105 | false 106 | 107 | 1 108 | Clean 109 | Clean 110 | ProjectExplorer.BuildSteps.Clean 111 | 112 | 2 113 | false 114 | 115 | Debug 116 | Qt4ProjectManager.Qt4BuildConfiguration 117 | 2 118 | 119 | 120 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Release 121 | 122 | 123 | true 124 | QtProjectManager.QMakeBuildStep 125 | false 126 | 127 | false 128 | false 129 | true 130 | 131 | 132 | true 133 | Qt4ProjectManager.MakeStep 134 | 135 | false 136 | 137 | 138 | false 139 | 140 | 2 141 | Build 142 | Build 143 | ProjectExplorer.BuildSteps.Build 144 | 145 | 146 | 147 | true 148 | Qt4ProjectManager.MakeStep 149 | 150 | true 151 | clean 152 | 153 | false 154 | 155 | 1 156 | Clean 157 | Clean 158 | ProjectExplorer.BuildSteps.Clean 159 | 160 | 2 161 | false 162 | 163 | Release 164 | Qt4ProjectManager.Qt4BuildConfiguration 165 | 0 166 | 167 | 168 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Profile 169 | 170 | 171 | true 172 | QtProjectManager.QMakeBuildStep 173 | true 174 | 175 | false 176 | true 177 | true 178 | 179 | 180 | true 181 | Qt4ProjectManager.MakeStep 182 | 183 | false 184 | 185 | 186 | false 187 | 188 | 2 189 | Build 190 | Build 191 | ProjectExplorer.BuildSteps.Build 192 | 193 | 194 | 195 | true 196 | Qt4ProjectManager.MakeStep 197 | 198 | true 199 | clean 200 | 201 | false 202 | 203 | 1 204 | Clean 205 | Clean 206 | ProjectExplorer.BuildSteps.Clean 207 | 208 | 2 209 | false 210 | 211 | Profile 212 | Qt4ProjectManager.Qt4BuildConfiguration 213 | 0 214 | 215 | 3 216 | 217 | 218 | 0 219 | Deploy 220 | Deploy 221 | ProjectExplorer.BuildSteps.Deploy 222 | 223 | 1 224 | ProjectExplorer.DefaultDeployConfiguration 225 | 226 | 1 227 | 228 | 229 | dwarf 230 | 231 | cpu-cycles 232 | 233 | 234 | 250 235 | 236 | -e 237 | cpu-cycles 238 | --call-graph 239 | dwarf,4096 240 | -F 241 | 250 242 | 243 | -F 244 | true 245 | 4096 246 | false 247 | false 248 | 1000 249 | 250 | true 251 | 252 | false 253 | false 254 | false 255 | false 256 | true 257 | 0.01 258 | 10 259 | true 260 | kcachegrind 261 | 1 262 | 25 263 | 264 | 1 265 | true 266 | false 267 | true 268 | valgrind 269 | 270 | 0 271 | 1 272 | 2 273 | 3 274 | 4 275 | 5 276 | 6 277 | 7 278 | 8 279 | 9 280 | 10 281 | 11 282 | 12 283 | 13 284 | 14 285 | 286 | 2 287 | 288 | Qt4ProjectManager.Qt4RunConfiguration:/home/leo/Desktop/NetworkFileTransfer-master/Client/Client.pro 289 | /home/leo/Desktop/NetworkFileTransfer-master/Client/Client.pro 290 | 291 | false 292 | 293 | false 294 | true 295 | true 296 | false 297 | false 298 | true 299 | 300 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Debug 301 | 302 | 1 303 | 304 | 305 | 306 | ProjectExplorer.Project.TargetCount 307 | 1 308 | 309 | 310 | ProjectExplorer.Project.Updater.FileVersion 311 | 22 312 | 313 | 314 | Version 315 | 22 316 | 317 | 318 | -------------------------------------------------------------------------------- /Client/debugonoroff.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUGONOROFF_H 2 | #define DEBUGONOROFF_H 3 | 4 | //#define __DEBUG__ 5 | 6 | #endif // DEBUGONOROFF_H 7 | -------------------------------------------------------------------------------- /Client/document.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Readme.txt 4 | 5 | 6 | -------------------------------------------------------------------------------- /Client/main.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include 3 | #include 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | Widget w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /Client/protocolcommand.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOCOLCOMMAND_H 2 | #define PROTOCOLCOMMAND_H 3 | 4 | #define _TRANSFER_ACK_ 0x0F00 //传输成功应答命令 5 | #define _TRANSFER_FILE_ 0x0F01 //传输文件命令 6 | #define _TRANSFER_LIST_ 0x0F02 //同步文件列表命令 7 | #define _DOWNLOAD_FILE_ 0x0F03 //下载文件命令 8 | 9 | 10 | #endif // PROTOCOLCOMMAND_H 11 | -------------------------------------------------------------------------------- /Client/widget.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include "ui_widget.h" 3 | #include "debugonoroff.h" 4 | #include "protocolcommand.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | Widget::Widget(QWidget *parent) : 14 | QWidget(parent), 15 | ui(new Ui::Widget) 16 | { 17 | ui->setupUi(this); 18 | 19 | this->setWindowTitle(tr("局域网文件传输客户端")); 20 | flag = false; 21 | SYNFlag = 0; 22 | DOWNFlag = 0; 23 | /*文件发送相关初始化*/ 24 | transferData.payloadSize = 64*1024; //每次发送64kb 25 | 26 | transferData.bytesWritten = 0; 27 | transferData.bytesToWrite = 0; 28 | 29 | clearVariation(); 30 | FILE *fp; 31 | if((fp = fopen("/home/leo/Desktop/NetworkFileTransfer-master/FileList/FILELIST.txt","w+"))==NULL) 32 | { 33 | qDebug()<<"Clear FILELIST.TXT error!"; 34 | } 35 | fclose(fp); 36 | tcpSocket = new QTcpSocket(); 37 | ui->ClientConnectPB->setText(tr("连接")); 38 | ui->DownloadPB->setEnabled(false); 39 | connect(tcpSocket,&QTcpSocket::readyRead,this,&Widget::receiveFile); 40 | connect(tcpSocket,&QTcpSocket::bytesWritten,this,&Widget::receiveFile); 41 | connect(tcpSocket,&QTcpSocket::disconnected,this,&Widget::socketDisconnected); 42 | } 43 | 44 | Widget::~Widget() 45 | { 46 | delete ui; 47 | } 48 | 49 | void Widget::on_ClientConnectPB_clicked() 50 | { 51 | if(ui->ClientConnectPB->text()==tr("连接")) 52 | { 53 | /*断开所有的连接*/ 54 | tcpSocket->abort(); 55 | /*连接服务器*/ 56 | tcpSocket->connectToHost(ui->ClientLineEdit->text(),8888); 57 | /*等待连接成功*/ 58 | if(!tcpSocket->waitForConnected(30000)) 59 | { 60 | qDebug()<<"Connection failed!"; 61 | return ; 62 | } 63 | flag = true; 64 | qDebug()<<"Connect successfully!"; 65 | ui->ClientConnectPB->setEnabled(true); 66 | ui->ClientConnectPB->setText(tr("断开")); 67 | } 68 | else 69 | { 70 | flag = false; 71 | /*断开连接*/ 72 | tcpSocket->disconnectFromHost(); 73 | /*修改按键的内容*/ 74 | ui->ClientConnectPB->setText(tr("连接")); 75 | } 76 | } 77 | 78 | void Widget::sendFile(QString path) 79 | { 80 | #if defined __DEBUG__ 81 | qDebug()<<"Socket send file name is"<open(QFile::ReadOnly)) 87 | { 88 | qDebug()<size(); 93 | #if defined __DEBUG__ 94 | qDebug()<<"发送文件的内容大小"<seek(0); 112 | /*填充实际的存储空间*/ 113 | sendOut << transferData.totalBytes<<_TRANSFER_FILE_ 114 | <write(transferData.inOrOutBlock); 123 | #if defined __DEBUG__ 124 | //qDebug()<0) 134 | { 135 | /*发送文件内容部分*/ 136 | transferData.inOrOutBlock = transferData.localFile->readAll(); 137 | tcpSocket->write(transferData.inOrOutBlock); 138 | transferData.inOrOutBlock.resize(0); 139 | } 140 | transferData.localFile->close(); 141 | } 142 | 143 | void Widget::receiveFile() 144 | { 145 | /*标志变量:下载标志变量 同步文件列表标志变量 传输文件标志变量*/ 146 | int downflag = 0 , synfilelistflag = 0, transferfileflag = 0; 147 | qint32 temp; 148 | /*如果没有数据可读,就直接返回*/ 149 | if(tcpSocket->bytesAvailable()<=0) 150 | { 151 | return; 152 | } 153 | QDataStream in(tcpSocket); 154 | in.setVersion(QDataStream::Qt_5_7); 155 | /*提取出总的大小、命令、文件名字的大小、文件名信息*/ 156 | if(transferData.bytesReceived <= sizeof(qint64)*3) 157 | { 158 | if(tcpSocket->bytesAvailable()>=sizeof(qint64)*3 159 | &&(transferData.fileNameSize==0)) 160 | { 161 | /*从套接字中提取总大小信息、命令、文件名字大小*/ 162 | in >> transferData.totalBytes >> transferData.command 163 | >> transferData.fileNameSize >> temp; 164 | transferData.bytesReceived += sizeof(qint64)*3; 165 | #if defined __DEBUG__ 166 | qDebug()<< "文件以及头信息总大小"<bytesAvailable()>=transferData.fileNameSize 172 | &&transferData.fileNameSize!=0) 173 | { 174 | /*提取接收的文件名字*/ 175 | in >> transferData.fileName; 176 | transferData.bytesReceived += transferData.fileNameSize; 177 | #if defined __DEBUG__ 178 | qDebug()<<"receive file name is"<bytesAvailable()) 184 | { 185 | qDebug()<<"socket have data!"; 186 | } 187 | #endif 188 | } 189 | } 190 | switch(transferData.command) 191 | { 192 | case _TRANSFER_FILE_ : 193 | { 194 | transferfileflag = 1; 195 | if(transferData.fileNameSize != 0) 196 | { 197 | if(SYNFlag == 1) 198 | { 199 | tempFileName = "./FileList/"; 200 | } 201 | else if(DOWNFlag == 1) 202 | { 203 | tempFileName = "./DownloadFile/"; 204 | } 205 | else 206 | { 207 | tempFileName = "./ClientFile/"; 208 | } 209 | tempFileName += transferData.fileName; 210 | /*创建本地文件*/ 211 | transferData.localFile = new QFile(tempFileName); 212 | if(!transferData.localFile->open(QFile::WriteOnly)) 213 | { 214 | qDebug()<<"open local file error!"; 215 | return; 216 | } 217 | } 218 | } 219 | case _TRANSFER_ACK_ : 220 | { 221 | qDebug()<<"Send file success!"; 222 | } 223 | break; 224 | default: 225 | qDebug()<<"Receive command nulity!"; 226 | } 227 | if(transferData.bytesReceived < transferData.totalBytes) 228 | { 229 | transferData.bytesReceived += tcpSocket->bytesAvailable(); 230 | transferData.inOrOutBlock = tcpSocket->readAll(); 231 | transferData.localFile->write(transferData.inOrOutBlock); 232 | transferData.inOrOutBlock.resize(0); 233 | } 234 | if(transferData.bytesReceived == transferData.totalBytes) 235 | { 236 | clearVariation(); 237 | if(transferfileflag == 1) 238 | { 239 | transferfileflag = 0; 240 | transferData.localFile->close(); 241 | qDebug()<<"Receive file success!"; 242 | } 243 | else if(synfilelistflag == 1) 244 | { 245 | synfilelistflag = 0; 246 | qDebug()<<"Request file list success!"; 247 | } 248 | else if(downflag == 1) 249 | { 250 | downflag = 0; 251 | qDebug()<<"Download file success!"; 252 | } 253 | } 254 | } 255 | void Widget::on_pushButton_clicked() 256 | { 257 | SYNFlag = 0; 258 | DOWNFlag = 0; 259 | transferData.fileName = QFileDialog::getOpenFileName(this); 260 | if(!transferData.fileName.isEmpty()) 261 | { 262 | qDebug()<listWidget->clear(); //每同步之前需要先进行清除工作 288 | while(input.readLineInto(&line)) //把所有文件名进行显示 289 | { 290 | ui->listWidget->addItem(line); 291 | } 292 | } 293 | 294 | 295 | //void Widget::displayFile(QTreeWidgetItem *parent,int num) 296 | //{ 297 | // QTreeWidgetItem *root,*item; 298 | // int i = 0; 299 | // while(fread(&dirInfo,sizeof(struct DirInformation),1,fp)) 300 | // { 301 | // if((dirInfo.topDir==1)&&(dirInfo.isDirectory==1))//添加顶层目录 302 | // { 303 | //#ifdef __DEBUG__ 304 | // qDebug()<<"This root directory!"; 305 | //#endif 306 | // root = new QTreeWidgetItem(ui->treeWidget); 307 | // root->setText(i++,QString(dirInfo.dirName)); 308 | // parent = root; 309 | // //this->displayFile(root,0); 310 | // } 311 | // else if((dirInfo.isDirectory==1)&&(dirInfo.topDir==0)) 312 | // { 313 | // item = new QTreeWidgetItem(); 314 | // item->setText(num++,QString(dirInfo.dirName)); 315 | //#ifdef __DEBUG__ 316 | // qDebug()<<"num ="<addChild(item); 319 | // displayFile(item,0); 320 | // } 321 | // else if((dirInfo.isFile==1)&&(dirInfo.topDir==0)) 322 | // { 323 | //#ifdef __DEBUG__ 324 | // qDebug()<<"num ="<setText(num++,QString(dirInfo.fileName)); 328 | // } 329 | // } 330 | //} 331 | //void Widget::DfsFolder(std::string path,int layer) 332 | //{ 333 | // _finddata_t file_info; 334 | // std::string current_path=path+"/*.*"; //也可以用/*来匹配所有 335 | // int handle=_findfirst(current_path.c_str(),&file_info); 336 | // /*返回值为-1则查找失败*/ 337 | // if(-1==handle) 338 | // { 339 | // std::cout<<"cannot match the path"<ClientLineEdit->clear(); 377 | ui->ClientConnectPB->setText(tr("连接")); 378 | } 379 | 380 | void Widget::on_SynFilePtn_clicked() 381 | { 382 | 383 | QString tempFileName; 384 | //tempFileName = "./FileList/"; 385 | /*初始化发送字节为0*/ 386 | clearVariation(); 387 | SYNFlag = 1; 388 | QDataStream sendOut(&transferData.inOrOutBlock,QIODevice::WriteOnly); 389 | 390 | /*设置版本*/ 391 | sendOut.setVersion(QDataStream::Qt_5_7); 392 | QString currentfilename; 393 | currentfilename = " "; 394 | /*保留总大小信息空间、文件名大小信息空间、然后输入文件名*/ 395 | sendOut << qint64(0) << qint64(0) << qint64(0) << currentfilename; 396 | /*总的大小是包含总大小信息、文件名大小信息、文件名和实际文件大小的总和*/ 397 | transferData.totalBytes += transferData.inOrOutBlock.size(); 398 | 399 | sendOut.device()->seek(0); 400 | /*填充实际的存储空间*/ 401 | sendOut << transferData.totalBytes << _TRANSFER_LIST_ 402 | << qint64((transferData.inOrOutBlock.size()-sizeof(qint64)*3)); 403 | 404 | qint64 sum = tcpSocket->write(transferData.inOrOutBlock); 405 | transferData.bytesToWrite = transferData.totalBytes - sum; 406 | #if defined __DEBUG__ 407 | qDebug()<<"sum"<listWidget->count()) 415 | { 416 | ui->DownloadPB->setEnabled(true); 417 | } 418 | else 419 | { 420 | ui->DownloadPB->setEnabled(false); 421 | } 422 | // this->displayFileListToWidget(); 423 | } 424 | 425 | 426 | void Widget::sleep(int ms) 427 | { 428 | QTime dieTime = QTime::currentTime().addMSecs(ms); 429 | while(QTime::currentTime()< dieTime) 430 | QCoreApplication::processEvents(QEventLoop::AllEvents,100); 431 | } 432 | 433 | void Widget::on_DownloadPB_clicked() 434 | { 435 | SYNFlag = 0; 436 | DOWNFlag = 1; 437 | //tempFileName = "./DownloadFile/"; 438 | /*获得要下载的文件名字*/ 439 | QString downloadfile = ui->listWidget->currentItem()->text(); 440 | if(downloadfile.isEmpty()) 441 | return; 442 | transferData.fileName = downloadfile; 443 | #if defined __DEBUG__ 444 | qDebug()<<"发送数据的总大小"<seek(0); 458 | /*填充实际的存储空间*/ 459 | sendOut << transferData.totalBytes << _DOWNLOAD_FILE_ 460 | << qint64((transferData.inOrOutBlock.size()-sizeof(qint64)*3)); 461 | int sum = tcpSocket->write(transferData.inOrOutBlock); 462 | transferData.bytesToWrite = transferData.totalBytes - sum; 463 | #if defined __DEBUG__ 464 | qDebug()<<"sum"< 5 | 6 | /*类的前置声明*/ 7 | class QFileDialog; 8 | class QFile; 9 | class QTcpSocket; 10 | class QTreeWidgetItem; 11 | namespace Ui { 12 | class Widget; 13 | } 14 | 15 | class Widget : public QWidget 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | explicit Widget(QWidget *parent = 0); 21 | ~Widget(); 22 | void sleep(int ms); //延时函数 23 | void sendFile(QString path); //文件头信息发送函数 24 | void clearVariation(); //初始化变量 25 | void diaplayFileListForListWidget(); 26 | //void displayFile(QTreeWidgetItem *parent,int num); //递归显示文件列表 27 | private slots: 28 | void receiveFile(); //文件接收函数 29 | void socketDisconnected(); //断开连接槽函数 30 | void on_ClientConnectPB_clicked(); //请求连接槽函数 31 | void on_SynFilePtn_clicked(); //文件同步槽函数 32 | void on_pushButton_clicked(); //上传文件槽函数 33 | void on_DownloadPB_clicked(); //下载文件按钮 34 | 35 | private: 36 | Ui::Widget *ui; 37 | QTcpSocket *tcpSocket; //套接字变量 38 | QString message; //存放数据大小信息 39 | bool flag; //是否可以同步目录列表,true可是同步,false不可以 40 | int SYNFlag; //请求文件同步标志位 41 | int DOWNFlag; //下载文件标志位 42 | QString tempFileName; 43 | struct rcvOrSendDataPack{ 44 | /*共用部分*/ 45 | QFile *localFile; //存放本地文件 46 | qint64 totalBytes; //存放总大小信息 47 | QString fileName; //存放文件名 48 | QByteArray inOrOutBlock; //数据缓冲区 49 | /*发送相关*/ 50 | qint64 bytesWritten; //已经发送数据大小 51 | qint64 bytesToWrite; //剩余数据的大小 52 | qint64 payloadSize; //每次发送数据的大小 53 | int command; //发送命令 54 | /*接收相关*/ 55 | qint64 bytesReceived; //已收到数据的大小 56 | qint64 fileNameSize; //文件名的大小信息 57 | }; 58 | struct rcvOrSendDataPack transferData; //数据结构体 59 | 60 | struct DirInformation{ 61 | char fileName[260]; //文件名字 62 | char dirName[260]; //目录名字 63 | unsigned int isDirectory; //是否是目录 64 | unsigned int isFile; //是否是文件 65 | unsigned int topDir; //是否是顶层目录 66 | }; 67 | struct DirInformation dirInfo; 68 | }; 69 | 70 | #endif // WIDGET_H 71 | -------------------------------------------------------------------------------- /Client/widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Widget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 429 10 | 471 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Widget 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 连接/断开 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 上传文件 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 0 55 | 0 56 | 57 | 58 | 59 | 同步文件列表 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 0 68 | 0 69 | 70 | 71 | 72 | 下载 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 chlinfeng1997 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux基于QT的局域网多线程数据传输系统(客户端+服务器): 2 | 3 |        在进行数据传输的过程中可以选择TCP或者UDP协议,TCP虽然相对而言比较复杂,具有三次握手进行连接以及四次分手断开连接,但具备可靠性,被大公司广泛使用,因此设计一种基于TCP的多线程数据传输系统来进行通信。展示效果:https://www.bilibili.com/video/BV1FK4y1M7Cq 4 |
5 | 6 | # 客户端: 7 | 1)登陆注册功能:点击账号登录,输入账号以及密码,与Mysql数据库中保存的账号信息进行校验,完成登录;点击账号注册,输入账号、密码、重复输入密码,向Mysql数据库中添加新的账号信息,完成注册,账号登录界面如图3-3所示,账号注册界面如图3-4所示。
8 | 2) 连接服务器功能:在IP框中输入IP地址,在PORT框中输入服务器端口号即可完成Socket连接;
9 | 3)上传文件功能:点击上传文件按钮,并将当前文件显示到文件信息中;
10 | 4)清除文件功能:在每个文件导入后,点击清除文件按钮,即可清空文件信息;
11 | 5)传输文件功能:点击传输文件按钮,即可通过TCP协议将文件传输到服务器上;
12 | 6)传输消息功能:在消息信息栏输入要传输的消息之后,点击传输消息,即可通过TCP协议进行传输;
13 | 7)显示消息功能:在完成消息传输之后,会在右边的消息对话中显示传输的消息信息;
14 | 8)清空功能:如果需要清除传输的消息,点击清空消息,即可将消息信息框内的信息清空。
15 | 9)运行日志显示功能:当客户端与服务器成功连接以及连接失败,客户端主动断开连接,客户端被动断开连接,客户端发送文件,客户端接收文件都会在运行日志栏中显示当前的时间以及操作。 16 | 17 | # 服务器: 18 | 1)显示连接客户端信息功能:在客户端状态一栏可以显示连接上的客户端信息,包括客户端IP地址以及端口,同时点击断开连接,即可断开对应的客户端;
19 | 2)选择文件功能:点击选择文件按钮,并将当前文件显示到文件信息中;
20 | 3)删除文件功能:在每个文件导入后,点击删除文件按钮,即可清空文件信息;
21 | 4)传输文件功能:点击传输文件按钮,即可通过TCP协议将文件传输到所有客户端上;
22 | 5)传输消息功能:在消息信息栏输入要传输的消息之后,点击传输消息,即可通过TCP协议进行传输;
23 | 6)显示消息功能:在完成消息传输之后,会在右边的消息对话中显示传输的消息信息;
24 | 7)清空功能:如果需要清除传输的消息,点击清空消息,即可将消息信息框内的信息清空。
25 | 8)运行日志显示功能:当客户端与服务器成功连接,服务器主动断开连接,客户端主动断开连接,服务器发送文件,服务器接收文件都会在运行日志栏中显示当前的时间以及操作。 26 | -------------------------------------------------------------------------------- /Server/Server_V2.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-08-06T18:00:22 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += network 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = Server_V2 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | clientaddress.cpp \ 17 | qnchatmessage.cpp \ 18 | widget.cpp \ 19 | myserver.cpp \ 20 | mysocket.cpp \ 21 | mythread.cpp 22 | 23 | HEADERS += widget.h \ 24 | clientaddress.h \ 25 | myserver.h \ 26 | mysocket.h \ 27 | mythread.h \ 28 | debugonoroff.h \ 29 | protocolcommand.h \ 30 | qnchatmessage.h 31 | 32 | FORMS += widget.ui 33 | 34 | RESOURCES += \ 35 | documents.qrc \ 36 | img.qrc 37 | -------------------------------------------------------------------------------- /Server/Server_V2.pro.autosave: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | QT += network 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | TARGET = Server_V2 6 | TEMPLATE = app 7 | 8 | 9 | SOURCES += main.cpp\ 10 | clientaddress.cpp \ 11 | qnchatmessage.cpp \ 12 | widget.cpp \ 13 | myserver.cpp \ 14 | mysocket.cpp \ 15 | mythread.cpp 16 | 17 | HEADERS += widget.h \ 18 | clientaddress.h \ 19 | myserver.h \ 20 | mysocket.h \ 21 | mythread.h \ 22 | debugonoroff.h \ 23 | protocolcommand.h \ 24 | qnchatmessage.h 25 | 26 | FORMS += widget.ui 27 | 28 | RESOURCES += \ 29 | documents.qrc \ 30 | img.qrc 31 | -------------------------------------------------------------------------------- /Server/Server_V2.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {801efd51-282a-4073-9e5f-4217bf3d15c6} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | true 60 | 61 | 62 | 63 | ProjectExplorer.Project.Target.0 64 | 65 | Desktop Qt 5.14.2 GCC 64bit 66 | Desktop Qt 5.14.2 GCC 64bit 67 | qt.qt5.5142.gcc_64_kit 68 | 0 69 | 0 70 | 0 71 | 72 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Debug 73 | 74 | 75 | true 76 | QtProjectManager.QMakeBuildStep 77 | true 78 | 79 | false 80 | false 81 | false 82 | 83 | 84 | true 85 | Qt4ProjectManager.MakeStep 86 | 87 | false 88 | 89 | 90 | false 91 | 92 | 2 93 | Build 94 | Build 95 | ProjectExplorer.BuildSteps.Build 96 | 97 | 98 | 99 | true 100 | Qt4ProjectManager.MakeStep 101 | 102 | true 103 | clean 104 | 105 | false 106 | 107 | 1 108 | Clean 109 | Clean 110 | ProjectExplorer.BuildSteps.Clean 111 | 112 | 2 113 | false 114 | 115 | Debug 116 | Qt4ProjectManager.Qt4BuildConfiguration 117 | 2 118 | 119 | 120 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Release 121 | 122 | 123 | true 124 | QtProjectManager.QMakeBuildStep 125 | false 126 | 127 | false 128 | false 129 | true 130 | 131 | 132 | true 133 | Qt4ProjectManager.MakeStep 134 | 135 | false 136 | 137 | 138 | false 139 | 140 | 2 141 | Build 142 | Build 143 | ProjectExplorer.BuildSteps.Build 144 | 145 | 146 | 147 | true 148 | Qt4ProjectManager.MakeStep 149 | 150 | true 151 | clean 152 | 153 | false 154 | 155 | 1 156 | Clean 157 | Clean 158 | ProjectExplorer.BuildSteps.Clean 159 | 160 | 2 161 | false 162 | 163 | Release 164 | Qt4ProjectManager.Qt4BuildConfiguration 165 | 0 166 | 167 | 168 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Profile 169 | 170 | 171 | true 172 | QtProjectManager.QMakeBuildStep 173 | true 174 | 175 | false 176 | true 177 | true 178 | 179 | 180 | true 181 | Qt4ProjectManager.MakeStep 182 | 183 | false 184 | 185 | 186 | false 187 | 188 | 2 189 | Build 190 | Build 191 | ProjectExplorer.BuildSteps.Build 192 | 193 | 194 | 195 | true 196 | Qt4ProjectManager.MakeStep 197 | 198 | true 199 | clean 200 | 201 | false 202 | 203 | 1 204 | Clean 205 | Clean 206 | ProjectExplorer.BuildSteps.Clean 207 | 208 | 2 209 | false 210 | 211 | Profile 212 | Qt4ProjectManager.Qt4BuildConfiguration 213 | 0 214 | 215 | 3 216 | 217 | 218 | 0 219 | Deploy 220 | Deploy 221 | ProjectExplorer.BuildSteps.Deploy 222 | 223 | 1 224 | ProjectExplorer.DefaultDeployConfiguration 225 | 226 | 1 227 | 228 | 229 | dwarf 230 | 231 | cpu-cycles 232 | 233 | 234 | 250 235 | 236 | -e 237 | cpu-cycles 238 | --call-graph 239 | dwarf,4096 240 | -F 241 | 250 242 | 243 | -F 244 | true 245 | 4096 246 | false 247 | false 248 | 1000 249 | 250 | true 251 | 252 | false 253 | false 254 | false 255 | false 256 | true 257 | 0.01 258 | 10 259 | true 260 | kcachegrind 261 | 1 262 | 25 263 | 264 | 1 265 | true 266 | false 267 | true 268 | valgrind 269 | 270 | 0 271 | 1 272 | 2 273 | 3 274 | 4 275 | 5 276 | 6 277 | 7 278 | 8 279 | 9 280 | 10 281 | 11 282 | 12 283 | 13 284 | 14 285 | 286 | 2 287 | 288 | Qt4ProjectManager.Qt4RunConfiguration:/home/leo/Desktop/Server_V2/Server_V2.pro 289 | /home/leo/Desktop/Server_V2/Server_V2.pro 290 | 291 | false 292 | 293 | false 294 | true 295 | true 296 | false 297 | false 298 | true 299 | 300 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Debug 301 | 302 | 1 303 | 304 | 305 | 306 | ProjectExplorer.Project.TargetCount 307 | 1 308 | 309 | 310 | ProjectExplorer.Project.Updater.FileVersion 311 | 22 312 | 313 | 314 | Version 315 | 22 316 | 317 | 318 | -------------------------------------------------------------------------------- /Server/clientaddress.cpp: -------------------------------------------------------------------------------- 1 | #include "clientaddress.h" 2 | 3 | clientAddress::clientAddress(QString IP, int Port) 4 | { 5 | clientIP = IP; 6 | clientPort = Port; 7 | QLabel *clientImg = new QLabel(this); 8 | QPixmap pixmap(":/img/child.png"); 9 | QPixmap scaledPixmap = pixmap.scaled(QSize(32,32), Qt::KeepAspectRatio); 10 | clientImg->setPixmap(scaledPixmap); 11 | clientImg->move(9,9); 12 | QLabel *clientIPLocation = new QLabel(this); 13 | clientIPLocation->setText("IP : " + IP); 14 | clientIPLocation->move(50,15); 15 | QLabel *clientPortLocation = new QLabel(this); 16 | clientPortLocation->setText("Port : " + QString::number(Port)); 17 | clientPortLocation->move(210,15); 18 | QPushButton *disconnectionButton = new QPushButton(this); 19 | disconnectionButton->setText("断开连接"); 20 | disconnectionButton->setFixedWidth(140); 21 | disconnectionButton->move(310,9); 22 | connect(disconnectionButton, &QPushButton::clicked, [=](){ 23 | emit clientAddressSignal(IP, clientPort); 24 | }); 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Server/clientaddress.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIENTADDRESS_H 2 | #define CLIENTADDRESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | class clientAddress : public QWidget 9 | { 10 | Q_OBJECT 11 | public: 12 | // explicit clientAddress(QWidget *parent = nullptr); 13 | clientAddress(QString IP, int Port); 14 | 15 | int clientAddressIndex = 0; //保存该clientAddress的索引 16 | QLabel *isloadLabel; 17 | QString clientIP; 18 | int clientPort; 19 | 20 | signals: 21 | void clientAddressSignal(QString IP, int clientPort); 22 | }; 23 | 24 | #endif // CLIENTADDRESS_H 25 | -------------------------------------------------------------------------------- /Server/debugonoroff.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUGONOROFF_H 2 | #define DEBUGONOROFF_H 3 | 4 | //#define __DEBUG__ 5 | 6 | #endif // DEBUGONOROFF_H 7 | -------------------------------------------------------------------------------- /Server/documents.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Readme.txt 4 | 5 | 6 | -------------------------------------------------------------------------------- /Server/img.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | img/child.png 4 | img/loading4.gif 5 | img/teacher.png 6 | 7 | 8 | -------------------------------------------------------------------------------- /Server/img/child.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chlinfeng1997/MultiThreadDataTransmission/bfb3c21126c05c2804a4d98e75d4ccbcade7ac17/Server/img/child.png -------------------------------------------------------------------------------- /Server/img/loading4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chlinfeng1997/MultiThreadDataTransmission/bfb3c21126c05c2804a4d98e75d4ccbcade7ac17/Server/img/loading4.gif -------------------------------------------------------------------------------- /Server/img/teacher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chlinfeng1997/MultiThreadDataTransmission/bfb3c21126c05c2804a4d98e75d4ccbcade7ac17/Server/img/teacher.png -------------------------------------------------------------------------------- /Server/main.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | Widget w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /Server/myserver.cpp: -------------------------------------------------------------------------------- 1 | #include "myserver.h" 2 | 3 | Myserver::Myserver(QObject *parent) 4 | { 5 | socketNum = 0; 6 | /*获得当前widget对象*/ 7 | widget = dynamic_cast(parent); 8 | } 9 | 10 | Myserver::~Myserver() 11 | { 12 | 13 | } 14 | 15 | void Myserver::incomingConnection(qintptr socketDescriptor) 16 | { 17 | /*添加连接的客户端到链表中*/ 18 | socketList.append(socketDescriptor); 19 | /*每建立一个客户端请求客户端数量加一*/ 20 | socketNum++; 21 | if(socketNum>3) 22 | socketNum = 1; 23 | 24 | /*创建一个线程用于执行与客户端的工作*/ 25 | Mythread *thread = new Mythread(socketDescriptor,socketNum,0); 26 | threadList.append(thread); 27 | /*关联线程断开客户端连接信号和GUI更新界面槽函数*/ 28 | connect(thread,&Mythread::closeClientConnectSignal,widget,&Widget::closeClientConnectSlot); 29 | /*添加客户端IP到GUI中进行显示*/ 30 | // connect(thread,&Mythread::addClientIPToGUISignal,widget,&Widget::addClientIPTGUISlot); 31 | /*更改消息传输状态到GUI中进行显示*/ 32 | connect(thread,&Mythread::sendStateDisplaySignal,widget,&Widget::sendStateDisplaySlot); 33 | /*添加客户端消息到GUI中进行显示*/ 34 | connect(thread,&Mythread::sendInfoDisplaySignal,widget,&Widget::sendInfoDisplaySlot); 35 | /*发送文件信号发送至线程*/ 36 | connect(widget,&Widget::sendFileWidgetSignal,thread,&Mythread::sendFileSlot); 37 | /*发送消息信号发送至线程*/ 38 | connect(widget,&Widget::sendInfoWidgetSignal,thread,&Mythread::sendInfoSlot); 39 | /*服务器端主动断开连接*/ 40 | // connect(widget,&Widget::clientDiconnectSignal,this,&Myserver::clientDisconnectSlot); 41 | connect(widget,&Widget::clientAddressWidgetSignal,this,&Myserver::clientDisconnectSlot); 42 | /*启动线程*/ 43 | thread->start(); 44 | /*添加日志*/ 45 | connect(thread,&Mythread::displayInfoToGUISignal,widget,&Widget::displayInfoTGUISlot); 46 | } 47 | 48 | void Myserver::clientDisconnectSlot(int ID) 49 | { 50 | /*服务器端主动断开客户端的连接根据断开的客户端编号与其线程关联槽函数*/ 51 | // qDebug() << "套接字"; 52 | // qDebug() << ID; 53 | // for(int i = 0; i < threadList.size(); i++) 54 | // { 55 | // qDebug() << threadList.at(i); 56 | // } 57 | QMetaObject::Connection dis = QObject::connect(this,&Myserver::clientDisconnectSignal, 58 | threadList[ID],&Mythread::clientDisconnectSlot); 59 | emit clientDisconnectSignal(); 60 | // threadList[ID-1]->disconnect(); 61 | /*取消信号槽*/ 62 | disconnect(dis); 63 | /*从客户端套接字列表中移除套接字*/ 64 | socketList.removeAt(ID); 65 | /*从线程列表中移除线程*/ 66 | Mythread * deleteThread = threadList.takeAt(ID); 67 | /*关闭线程*/ 68 | deleteThread->exit(0); 69 | deleteThread->wait(); 70 | // qDebug() << socketList.size(); 71 | // qDebug() << threadList.size(); 72 | // qDebug() << "套接字now"; 73 | // for(int i = 0; i < socketList.size(); i++) 74 | // { 75 | // qDebug() << socketList.at(i); 76 | // } 77 | } 78 | -------------------------------------------------------------------------------- /Server/myserver.h: -------------------------------------------------------------------------------- 1 | #ifndef MYSERVER_H 2 | #define MYSERVER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "widget.h" 8 | #include "mythread.h" 9 | #include "debugonoroff.h" 10 | #include "clientaddress.h" 11 | class Widget; 12 | class Mythread; 13 | class Myserver : public QTcpServer 14 | { 15 | Q_OBJECT 16 | public: 17 | Myserver(QObject *parent); 18 | ~Myserver(); 19 | /*存储建立链接的客户端套接字*/ 20 | QListsocketList; 21 | /*存储线程*/ 22 | QListthreadList; 23 | /*存储客户端IP地址*/ 24 | QListsocketIP; 25 | /*记录客户端数量*/ 26 | int socketNum; 27 | protected: 28 | void incomingConnection(qintptr socketDescriptor); 29 | signals: 30 | /*客户端被动断开连接信号*/ 31 | void clientDisconnectSignal(); 32 | public slots: 33 | /*客户端被动断开连接槽函数*/ 34 | void clientDisconnectSlot(int ID); 35 | private: 36 | Widget *widget; //指向GUI的指针 37 | }; 38 | 39 | #endif // MYSERVER_H 40 | -------------------------------------------------------------------------------- /Server/mysocket.cpp: -------------------------------------------------------------------------------- 1 | #include "mysocket.h" 2 | #include 3 | #include "protocolcommand.h" 4 | #include 5 | #include 6 | Mysocket::Mysocket(int socket, int ID,QObject *parent) 7 | :QTcpSocket(parent), socketDescriptor(socket) 8 | { 9 | socketID = ID; 10 | clearVariation(); 11 | QObject::connect(this,&Mysocket::readyRead,this,&Mysocket::reveiveData); 12 | } 13 | 14 | Mysocket::~Mysocket() 15 | { 16 | 17 | } 18 | 19 | void Mysocket::sendFile(QString path) 20 | { 21 | /*初始化发送字节为0*/ 22 | transferData.bytesWritten = 0; 23 | transferData.fileName = path; 24 | transferData.localFile = new QFile(path); 25 | if(!transferData.localFile->open(QFile::ReadOnly)) 26 | { 27 | qDebug()<size();//获取文件大小 32 | 33 | QDataStream sendOut(&transferData.inOrOutBlock,QIODevice::WriteOnly); 34 | 35 | sendOut.setVersion(QDataStream::Qt_5_7); //设置版本 36 | /*获得文件名称*/ 37 | QString currentFilename = transferData.fileName.right(transferData.fileName.size() 38 | -transferData.fileName.lastIndexOf('/')-1); 39 | 40 | /*保留总大小信息空间、命令、文件名大小信息空间、然后输入文件名*/ 41 | sendOut << qint64(0) << qint64(0) << qint64(0)<< currentFilename; 42 | /*总的大小*/ 43 | transferData.totalBytes += transferData.inOrOutBlock.size(); 44 | 45 | sendOut.device()->seek(0); 46 | /*填充实际的存储空间*/ 47 | sendOut << transferData.totalBytes<<_TRANSFER_FILE_ 48 | <0) 57 | { 58 | /*发送文件内容部分*/ 59 | transferData.inOrOutBlock = transferData.localFile->readAll(); 60 | write(transferData.inOrOutBlock); 61 | transferData.inOrOutBlock.resize(0); 62 | } 63 | transferData.localFile->close(); 64 | emit sendStateDisplaySignal("服务器发送文件成功", ""); 65 | } 66 | 67 | void Mysocket::sendMSG(QString msg, QString IPAddress) 68 | { 69 | emit sendStateDisplaySignal("服务器开始发送消息", msg); 70 | /*确保连接依然有效*/ 71 | if(!isValid()) 72 | { 73 | qDebug()<<"Already disconnected!"; 74 | return; 75 | } 76 | qDebug() << msg; 77 | transferData.totalBytes = 0; 78 | /*使用数据流写入数据*/ 79 | QDataStream outPut(&transferData.inOrOutBlock,QIODevice::WriteOnly); 80 | outPut.setVersion(QDataStream::Qt_5_7); 81 | transferData.totalBytes = msg.toUtf8().size(); 82 | // qDebug() << transferData.totalBytes; 83 | 84 | /*保留总大小信息空间、命令、文件名大小信息空间、然后输入文件名*/ 85 | outPut << qint64(0) << qint64(0) << qint64(0) << msg << IPAddress; 86 | // qDebug() << transferData.inOrOutBlock; 87 | // qDebug() << msg; 88 | // qDebug() << IPAddress << "6666"; 89 | /*消息的总大小*/ 90 | transferData.totalBytes += transferData.inOrOutBlock.size(); 91 | /*定位到数据流的开始位置*/ 92 | outPut.device()->seek(0); 93 | /*填充实际的存储空间*/ 94 | outPut << transferData.totalBytes<<_TRANSFER_INFO_ 95 | <0) 104 | // { 105 | // /*发送文件内容部分*/ 106 | // transferData.inOrOutBlock = transferData.localFile->readAll(); 107 | // write(transferData.inOrOutBlock); 108 | // transferData.inOrOutBlock.resize(0); 109 | // } 110 | // else 111 | // { 112 | // transferData.inOrOutBlock.resize(0); 113 | // } 114 | 115 | } 116 | 117 | void Mysocket::reveiveData() 118 | { 119 | /*标志变量:下载标志变量 同步文件列表标志变量 传输文件标志变量*/ 120 | int transferfileflag = 0; 121 | QString ip; 122 | qint32 temp; 123 | /*如果没有数据可读,就直接返回*/ 124 | if(bytesAvailable()<=0) 125 | { 126 | return; 127 | } 128 | 129 | QDataStream in(this); 130 | in.setVersion(QDataStream::Qt_5_14); 131 | 132 | /*提取出总的大小、命令、文件名字的大小、文件名信息*/ 133 | if(transferData.bytesReceived <= sizeof(qint64)*3) 134 | { 135 | 136 | if(bytesAvailable()>=sizeof(qint64)*3 137 | &&(transferData.fileNameSize==0)) 138 | { 139 | /*从套接字中提取总大小信息、命令、文件名字大小*/ 140 | in >> transferData.totalBytes >> transferData.command 141 | >> transferData.fileNameSize >> temp; 142 | transferData.bytesReceived += sizeof(qint64)*3; 143 | 144 | } 145 | if(bytesAvailable()>=transferData.fileNameSize 146 | &&transferData.fileNameSize!=0) 147 | { 148 | /*提取接收的文件名字*/ 149 | in >> transferData.fileName >> ip; 150 | transferData.bytesReceived += transferData.fileNameSize; 151 | 152 | } 153 | } 154 | switch(transferData.command) 155 | { 156 | case _TRANSFER_FILE_ : 157 | { 158 | transferfileflag = 1; 159 | if(transferData.fileNameSize != 0) 160 | { 161 | QString tempfilename("/home/leo/Desktop/ReceiveFile/"); 162 | tempfilename += transferData.fileName; 163 | /*创建本地文件*/ 164 | transferData.localFile = new QFile(tempfilename); 165 | if(!transferData.localFile->open(QFile::WriteOnly)) 166 | { 167 | qDebug()<<"open local file error!"; 168 | return; 169 | } 170 | if(transferData.bytesReceived < transferData.totalBytes) 171 | { 172 | transferData.bytesReceived += bytesAvailable(); 173 | transferData.inOrOutBlock = readAll(); 174 | transferData.localFile->write(transferData.inOrOutBlock); 175 | transferData.inOrOutBlock.resize(0); 176 | } 177 | if(transferData.bytesReceived == transferData.totalBytes) 178 | { 179 | clearVariation(); 180 | if(transferfileflag == 1) 181 | { 182 | transferfileflag = 0; 183 | transferData.localFile->close(); 184 | qDebug()<<"Receive file success!"; 185 | emit sendStateDisplaySignal("服务器接收文件成功", ""); 186 | } 187 | } 188 | } 189 | } 190 | break; 191 | case _TRANSFER_INFO_ : 192 | { 193 | QString clientInfo = transferData.fileName; 194 | // QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 195 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 196 | // ui->textEdit->append(current_date + " —— " + "客户端接收消息成功"); 197 | // QMessageBox::about(NULL, "服务器消息", serverInfo); 198 | emit sendInfoDisplaySignal(clientInfo, ip); 199 | transferData.bytesReceived = 0; 200 | transferData.fileNameSize = 0; 201 | transferData.inOrOutBlock.resize(0); 202 | qDebug()<<"Receive info success!"; 203 | } 204 | break; 205 | default: 206 | qDebug()<<"Receive command nulity!"; 207 | break; 208 | } 209 | } 210 | 211 | void Mysocket::clientDisconnectSlot() 212 | { 213 | this->disconnectFromHost(); 214 | this->close(); 215 | // emit clientDisconnectSignal(); 216 | } 217 | 218 | void Mysocket::clearVariation() 219 | { 220 | transferData.totalBytes = 0; 221 | transferData.bytesReceived = 0; 222 | transferData.fileNameSize = 0; 223 | transferData.inOrOutBlock.resize(0); 224 | transferData.payloadSize = 1024 * 64; //每次发送64kb 225 | transferData.bytesWritten = 0; 226 | transferData.bytesToWrite = 0; 227 | } 228 | 229 | QString Mysocket::findDownloadFile(QString path, QString fileName) 230 | { 231 | if(path.isEmpty()||fileName.isEmpty()) 232 | return QString(); 233 | QDir dir; 234 | QStringList filters; 235 | filters << fileName; 236 | dir.setPath(path); 237 | dir.setNameFilters(filters); 238 | QDirIterator iter(dir,QDirIterator::Subdirectories); 239 | while(iter.hasNext()) 240 | { 241 | iter.next(); 242 | QFileInfo info = iter.fileInfo(); 243 | if(info.isFile()) 244 | { 245 | return info.absoluteFilePath(); 246 | } 247 | } 248 | return QString(); 249 | } 250 | -------------------------------------------------------------------------------- /Server/mysocket.h: -------------------------------------------------------------------------------- 1 | #ifndef MYSOCKET_H 2 | #define MYSOCKET_H 3 | 4 | #include 5 | #include "debugonoroff.h" 6 | #include 7 | 8 | 9 | class Mysocket : public QTcpSocket 10 | { 11 | Q_OBJECT 12 | public: 13 | Mysocket(int socket,int ID,QObject *parent = 0); 14 | ~Mysocket(); 15 | /*发送文件*/ 16 | void sendFile(QString path); 17 | /*发送消息*/ 18 | void sendMSG(QString msg, QString IPAddress); 19 | /*初始化变量*/ 20 | void clearVariation(); 21 | /*查找要下载的文件*/ 22 | QString findDownloadFile(QString path,QString fileName); 23 | signals: 24 | void clientDisconnectSignal(); 25 | /*发送状态在GUI中显示*/ 26 | void sendStateDisplaySignal(QString msg, QString info); 27 | /*发送消息在GUI中显示*/ 28 | void sendInfoDisplaySignal(QString clientInfo, QString ip); 29 | public slots: 30 | /*数据接收槽函数*/ 31 | void reveiveData(); 32 | /*断开连接*/ 33 | void clientDisconnectSlot(); 34 | private: 35 | /*客户端编号*/ 36 | int socketID; 37 | int socketDescriptor; 38 | /*数据协议包*/ 39 | struct rcvOrSendDataPack{ 40 | /*共用部分*/ 41 | QFile *localFile; //存放本地文件 42 | qint64 totalBytes; //存放总大小信息 43 | QString fileName; //存放文件名 44 | QByteArray inOrOutBlock; //数据缓冲区 45 | /*发送相关*/ 46 | qint64 bytesWritten; //已经发送数据大小 47 | qint64 bytesToWrite; //剩余数据的大小 48 | qint64 payloadSize; //每次发送数据的大小 49 | /*接收相关*/ 50 | qint64 bytesReceived; //已收到数据的大小 51 | qint64 fileNameSize; //文件名的大小信息 52 | int command; //接收的命令 53 | }; 54 | struct rcvOrSendDataPack transferData; //数据结构体 55 | }; 56 | 57 | #endif // MYSOCKET_H 58 | -------------------------------------------------------------------------------- /Server/mythread.cpp: -------------------------------------------------------------------------------- 1 | #include "mythread.h" 2 | #include 3 | #include 4 | #include "debugonoroff.h" 5 | #include "protocolcommand.h" 6 | Mythread::Mythread(int socketDes,int ID,QObject *parent): 7 | QThread(parent), socketDescriptor(socketDes) 8 | { 9 | clientID = ID; 10 | socketDescriptor = socketDes; 11 | } 12 | 13 | void Mythread::run() 14 | { 15 | /*保存客户端IP地址*/ 16 | QString clientIP; 17 | /*保存客户端状态*/ 18 | int clientState; 19 | /*创建套接字对象*/ 20 | Mysocket *socket = new Mysocket(socketDescriptor,clientID,0); 21 | /*设置服务器监听到来的客户端的套接字描述符*/ 22 | if(!socket->setSocketDescriptor(socketDescriptor)) 23 | return; 24 | 25 | QObject::connect(socket,&Mysocket::disconnected,this,&Mythread::closeClientConnectSlot); 26 | QObject::connect(socket,&Mysocket::sendStateDisplaySignal,this,&Mythread::sendStateDisplaySlot); 27 | QObject::connect(socket,&Mysocket::sendInfoDisplaySignal,this,&Mythread::sendInfoDisplaySlot); 28 | QObject::connect(this,&Mythread::sendFileSignal,socket,&Mysocket::sendFile); 29 | QObject::connect(this,&Mythread::sendInfoSignal,socket,&Mysocket::sendMSG); 30 | QObject::connect(this,&Mythread::clientDisconnectSignal,socket,&Mysocket::clientDisconnectSlot); 31 | /*获得客户端的IP地址*/ 32 | clientIP = socket->peerAddress().toString(); 33 | /*获得客户端的端口号*/ 34 | clientPort = socket->peerPort(); 35 | clientState = socket->state(); 36 | 37 | if(!clientIP.isEmpty()) 38 | { 39 | /*只保留32位的点分十进制IP值*/ 40 | clientIP = clientIP.right(clientIP.length()-7); 41 | clientIp = clientIP; 42 | current_date_time = QDateTime::currentDateTime(); 43 | /*回传客户端IP地址和ID到GUI显示信号*/ 44 | emit addClientIPToGUISignal(clientIP,clientPort,clientID,clientState); 45 | emit displayInfoToGUISignal(clientIP,clientPort,clientState,current_date_time); 46 | } 47 | else 48 | { 49 | qDebug()<< "Get client IP failed!"; 50 | } 51 | 52 | exec(); 53 | } 54 | 55 | void Mythread::closeClientConnectSlot() 56 | { 57 | /*向GUI发射套接字断开连接信号更新界面*/ 58 | current_date_time = QDateTime::currentDateTime(); 59 | emit closeClientConnectSignal(clientIp, clientPort, current_date_time); 60 | } 61 | 62 | void Mythread::clientDisconnectSlot() 63 | { 64 | /*关闭线程*/ 65 | // this->quit(); 66 | emit clientDisconnectSignal(); 67 | } 68 | 69 | void Mythread::sendStateDisplaySlot(QString msg, QString info) 70 | { 71 | emit sendStateDisplaySignal(msg, info); 72 | } 73 | 74 | void Mythread::sendInfoDisplaySlot(QString clientInfo, QString ip) 75 | { 76 | emit sendInfoDisplaySignal(clientInfo, ip); 77 | } 78 | 79 | void Mythread::sendFileSlot(QString filename) 80 | { 81 | emit sendFileSignal(filename); 82 | } 83 | 84 | void Mythread::sendInfoSlot(QString info) 85 | { 86 | emit sendInfoSignal(info, clientIp); 87 | } 88 | -------------------------------------------------------------------------------- /Server/mythread.h: -------------------------------------------------------------------------------- 1 | #ifndef MYTHREAD_H 2 | #define MYTHREAD_H 3 | 4 | #include 5 | #include 6 | #include "mysocket.h" 7 | #include "debugonoroff.h" 8 | 9 | class Mythread : public QThread 10 | { 11 | Q_OBJECT 12 | public: 13 | Mythread(int socketDes,int ID,QObject *parent); 14 | protected: 15 | void run(); 16 | signals: 17 | /*添加客户端IP地址到GUI*/ 18 | void addClientIPToGUISignal(QString CIP, int CPort, int ID, int state); 19 | /*客户端主动断开连接信号*/ 20 | void closeClientConnectSignal(QString clientIp, int clientPort, QDateTime current_date_time); 21 | /*客户端被动断开连接*/ 22 | void clientDisconnectSignal(); 23 | /*获得文件列表信号*/ 24 | void getFileListSignal(QString filelist); 25 | /*发送文件信号*/ 26 | void sendFileSignal(QString filename); 27 | /*发送消息信号*/ 28 | void sendInfoSignal(QString info, QString IPAddress); 29 | /*显示日志信号*/ 30 | void displayInfoToGUISignal(QString CIP,int CPort,int state,QDateTime current_time); 31 | /*发送状态显示到GUI*/ 32 | void sendStateDisplaySignal(QString msg, QString info); 33 | /*发送消息显示到GUI*/ 34 | void sendInfoDisplaySignal(QString clientInfo, QString ip); 35 | public slots: 36 | /*客户端主动断开连接槽*/ 37 | void closeClientConnectSlot(); 38 | /*客户端被动断开连接槽函数*/ 39 | void clientDisconnectSlot(); 40 | /*发送文件槽函数*/ 41 | void sendFileSlot(QString filename); 42 | /*发送消息槽函数*/ 43 | void sendInfoSlot(QString info); 44 | /*发送状态显示到GUI槽函数*/ 45 | void sendStateDisplaySlot(QString msg, QString info); 46 | /*发送消息显示到GUI槽函数*/ 47 | void sendInfoDisplaySlot(QString clientInfo, QString ip); 48 | private: 49 | Mysocket *socket; 50 | /*记录客户端数量*/ 51 | int clientID; 52 | /*记录客户端IP*/ 53 | QString clientIp; 54 | /*记录客户端端口号*/ 55 | int clientPort; 56 | quintptr socketDescriptor; 57 | QDateTime current_date_time; 58 | 59 | struct rcvOrSendDataPack{ 60 | /*共用部分*/ 61 | QFile *localFile; //存放本地文件 62 | qint64 totalBytes; //存放总大小信息 63 | QString fileName; //存放文件名 64 | QByteArray inOrOutBlock; //数据缓冲区 65 | /*发送相关*/ 66 | qint64 bytesWritten; //已经发送数据大小 67 | qint64 bytesToWrite; //剩余数据的大小 68 | qint64 payloadSize; //每次发送数据的大小 69 | /*接收相关*/ 70 | qint64 bytesReceived; //已收到数据的大小 71 | qint64 fileNameSize; //文件名的大小信息 72 | qint64 command; //接收的命令 73 | }; 74 | struct rcvOrSendDataPack transferData; //数据结构体 75 | }; 76 | 77 | #endif // MYTHREAD_H 78 | -------------------------------------------------------------------------------- /Server/protocolcommand.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOCOLCOMMAND_H 2 | #define PROTOCOLCOMMAND_H 3 | 4 | #define _TRANSFER_ACK_ 0x0F00 //传输成功应答命令 5 | #define _TRANSFER_FILE_ 0x0F01 //传输文件命令 6 | #define _TRANSFER_LIST_ 0x0F02 //同步文件列表命令 7 | #define _DOWNLOAD_FILE_ 0x0F03 //下载文件命令 8 | #define _TRANSFER_INFO_ 0x0F04 //传输消息命令 9 | 10 | 11 | #endif // PROTOCOLCOMMAND_H 12 | -------------------------------------------------------------------------------- /Server/qnchatmessage.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------- 2 | # 3 | # Project created by QtCreator 4 | # Author: 沙振宇 5 | # CreateTime: 2018-07-23 6 | # UpdateTime: 2019-12-27 7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现 8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832 9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt 10 | # 11 | #-------------------------------------------------*/ 12 | #include "qnchatmessage.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | QNChatMessage::QNChatMessage(QWidget *parent, QString serverIP) : QWidget(parent) 23 | { 24 | QFont te_font = this->font(); 25 | te_font.setFamily("MicrosoftYaHei"); 26 | te_font.setPointSize(12); 27 | serverIPAddress = serverIP; 28 | get_local_Ip(); 29 | // te_font.setWordSpacing(0); 30 | // te_font.setLetterSpacing(QFont::PercentageSpacing,0); 31 | // te_font.setLetterSpacing(QFont::PercentageSpacing, 100); //300%,100为默认 //设置字间距% 32 | // te_font.setLetterSpacing(QFont::AbsoluteSpacing, 0); //设置字间距为3像素 //设置字间距像素值 33 | this->setFont(te_font); 34 | m_leftPixmap = QPixmap(":/img/child.png"); 35 | m_rightPixmap = QPixmap(":/img/teacher.png"); 36 | 37 | m_loadingMovie = new QMovie(this); 38 | m_loadingMovie->setFileName(":/img/loading4.gif"); 39 | m_loading = new QLabel(this); 40 | m_loading->setMovie(m_loadingMovie); 41 | m_loading->resize(16,16); 42 | m_loading->setAttribute(Qt::WA_TranslucentBackground , true); 43 | m_loading->setAutoFillBackground(false); 44 | } 45 | 46 | void QNChatMessage::get_local_Ip() 47 | { 48 | QList ipAddressesList = QNetworkInterface::allAddresses(); 49 | // use the first non-localhost IPv4 address 50 | for (int i = 0; i < ipAddressesList.size(); ++i) { 51 | qDebug()<hide(); 67 | m_loadingMovie->stop(); 68 | m_isSending = true; 69 | } 70 | 71 | void QNChatMessage::setText(QString text, QString time, QSize allSize, QNChatMessage::User_Type userType) 72 | { 73 | m_msg = text; 74 | m_userType = userType; 75 | m_time = time; 76 | m_curTime = QDateTime::fromTime_t(time.toInt()).toString("hh:mm"); 77 | m_allSize = allSize; 78 | if(userType == User_Me) { 79 | if(!m_isSending) { 80 | m_loading->move(m_kuangRightRect.x() - m_loading->width() - 10, m_kuangRightRect.y()+m_kuangRightRect.height()/2- m_loading->height()/2); 81 | m_loading->show(); 82 | m_loadingMovie->start(); 83 | } 84 | } else { 85 | m_loading->hide(); 86 | } 87 | 88 | this->update(); 89 | } 90 | 91 | QSize QNChatMessage::fontRect(QString str) 92 | { 93 | m_msg = str; 94 | int minHei = 30; 95 | int iconWH = 40; 96 | int iconSpaceW = 20; 97 | int iconRectW = 5; 98 | int iconTMPH = 10; 99 | int sanJiaoW = 6; 100 | int kuangTMP = 20; 101 | int textSpaceRect = 12; 102 | m_nameWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW); 103 | m_kuangWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW); 104 | m_textWidth = m_kuangWidth - 2 * textSpaceRect; 105 | m_spaceWid = this->width() - m_textWidth; 106 | m_iconLeftRect = QRect(iconSpaceW, iconTMPH, iconWH, iconWH); 107 | m_iconRightRect = QRect(this->width() - iconSpaceW - iconWH, iconTMPH, iconWH, iconWH); 108 | 109 | QSize size = getRealString(m_msg); // 整个的size 110 | QFontMetrics fontMetrics(QFont("Microsoft YaHei", 8, QFont::Normal)); 111 | int clientIPWidth = fontMetrics.horizontalAdvance(ipAddress); 112 | int serverIPWidth = fontMetrics.horizontalAdvance(serverIPAddress); 113 | qDebug() << "fontRect Size:" << size << clientIPWidth; 114 | int hei = size.height() < minHei ? minHei : size.height(); 115 | /*三角形*/ 116 | m_sanjiaoLeftRect = QRect(iconWH+iconSpaceW+iconRectW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight); 117 | m_sanjiaoRightRect = QRect(this->width() - iconRectW - iconWH - iconSpaceW - sanJiaoW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight); 118 | 119 | if(size.width() < (m_textWidth+m_spaceWid)) { 120 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5); 121 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth, 122 | m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5); 123 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight); 124 | m_kuangRightRect.setRect(this->width() - size.width() + m_spaceWid - 2*textSpaceRect - iconWH - iconSpaceW - iconRectW - sanJiaoW, 125 | m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight); 126 | } else { 127 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5); 128 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth, m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5); 129 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight); 130 | m_kuangRightRect.setRect(iconWH + kuangTMP + iconSpaceW + iconRectW - sanJiaoW, m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight); 131 | } 132 | /*消息框*/ 133 | m_textLeftRect.setRect(m_kuangLeftRect.x()+textSpaceRect,m_kuangLeftRect.y()+iconTMPH, 134 | m_kuangLeftRect.width()-2*textSpaceRect,m_kuangLeftRect.height()-2*iconTMPH); 135 | m_textRightRect.setRect(m_kuangRightRect.x()+textSpaceRect,m_kuangRightRect.y()+iconTMPH, 136 | m_kuangRightRect.width()-2*textSpaceRect,m_kuangRightRect.height()-2*iconTMPH); 137 | 138 | return QSize(size.width(), hei); 139 | } 140 | 141 | QSize QNChatMessage::getRealString(QString src) 142 | { 143 | QFontMetricsF fm(this->font()); 144 | m_lineHeight = fm.lineSpacing(); 145 | int nCount = src.count("\n"); 146 | int nMaxWidth = 0; 147 | if(nCount == 0) { 148 | nMaxWidth = qCeil(fm.width(src)); 149 | QString value = src; 150 | if(nMaxWidth > m_textWidth) { 151 | qDebug() << "2222"; 152 | nMaxWidth = m_textWidth; 153 | int size = m_textWidth / fm.width(" "); 154 | int num = fm.width(value) / m_textWidth; 155 | num = ( fm.width(value) ) / m_textWidth; 156 | nCount += num; 157 | QString temp = ""; 158 | for(int i = 0; i < num; i++) { 159 | temp += value.mid(i*size, (i+1)*size) + "\n"; 160 | } 161 | src.replace(value, temp); 162 | } 163 | } else { 164 | for(int i = 0; i < (nCount + 1); i++) { 165 | QString value = src.split("\n").at(i); 166 | nMaxWidth = qCeil(fm.width(value)) > nMaxWidth ? qCeil(fm.width(value)) : nMaxWidth; 167 | if(fm.width(value) > m_textWidth) { 168 | nMaxWidth = m_textWidth; 169 | int size = m_textWidth / fm.width(" "); 170 | int num = fm.width(value) / m_textWidth; 171 | num = ((i+num)*fm.width(" ") + fm.width(value)) / m_textWidth; 172 | nCount += num; 173 | QString temp = ""; 174 | for(int i = 0; i < num; i++) { 175 | temp += value.mid(i*size, (i+1)*size) + "\n"; 176 | } 177 | src.replace(value, temp); 178 | } 179 | } 180 | } 181 | return QSize(nMaxWidth+m_spaceWid, (nCount + 1) * m_lineHeight+2*m_lineHeight); 182 | } 183 | 184 | void QNChatMessage::paintEvent(QPaintEvent *event) 185 | { 186 | Q_UNUSED(event); 187 | 188 | QPainter painter(this); 189 | painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿 190 | painter.setPen(Qt::NoPen); 191 | painter.setBrush(QBrush(Qt::gray)); 192 | 193 | if(m_userType == User_Type::User_She) { // 用户 194 | //头像 195 | // painter.drawRoundedRect(m_iconLeftRect,m_iconLeftRect.width(),m_iconLeftRect.height()); 196 | painter.drawPixmap(m_iconLeftRect, m_leftPixmap); 197 | 198 | //框加边 199 | QColor col_KuangB(234, 234, 234); 200 | painter.setBrush(QBrush(col_KuangB)); 201 | painter.drawRoundedRect(m_kuangLeftRect.x()-1,m_kuangLeftRect.y()-1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4); 202 | //框 203 | QColor col_Kuang(255,255,255); 204 | painter.setBrush(QBrush(col_Kuang)); 205 | painter.drawRoundedRect(m_kuangLeftRect,4,4); 206 | 207 | //三角 208 | QPointF points[3] = { 209 | QPointF(m_sanjiaoLeftRect.x(), 30), 210 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 25), 211 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 35), 212 | }; 213 | QPen pen; 214 | pen.setColor(col_Kuang); 215 | painter.setPen(pen); 216 | painter.drawPolygon(points, 3); 217 | 218 | //三角加边 219 | QPen penSanJiaoBian; 220 | penSanJiaoBian.setColor(col_KuangB); 221 | painter.setPen(penSanJiaoBian); 222 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 24)); 223 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 36)); 224 | 225 | //内容 226 | QPen penText; 227 | penText.setColor(QColor(51,51,51)); 228 | painter.setPen(penText); 229 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter); 230 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 231 | painter.setFont(this->font()); 232 | painter.drawText(m_textLeftRect, m_msg,option); 233 | 234 | QPen penName; 235 | penName.setColor(QColor(192,192,192)); 236 | painter.setPen(penName); 237 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter); 238 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 239 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal)); 240 | painter.drawText(m_nameLeftRect, serverIPAddress, optionName); 241 | } else if(m_userType == User_Type::User_Me) { // 自己 242 | //头像 243 | // painter.drawRoundedRect(m_iconRightRect,m_iconRightRect.width(),m_iconRightRect.height()); 244 | painter.drawPixmap(m_iconRightRect, m_rightPixmap); 245 | 246 | //框 247 | QColor col_Kuang(75,164,242); 248 | painter.setBrush(QBrush(col_Kuang)); 249 | painter.drawRoundedRect(m_kuangRightRect,4,4); 250 | 251 | //三角 252 | QPointF points[3] = { 253 | QPointF(m_sanjiaoRightRect.x()+m_sanjiaoRightRect.width(), 30), 254 | QPointF(m_sanjiaoRightRect.x(), 25), 255 | QPointF(m_sanjiaoRightRect.x(), 35), 256 | }; 257 | QPen pen; 258 | pen.setColor(col_Kuang); 259 | painter.setPen(pen); 260 | painter.drawPolygon(points, 3); 261 | 262 | //内容 263 | QPen penText; 264 | penText.setColor(Qt::white); 265 | painter.setPen(penText); 266 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter); 267 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 268 | painter.setFont(this->font()); 269 | painter.drawText(m_textRightRect,m_msg,option); 270 | 271 | QPen penName; 272 | penName.setColor(QColor(192,192,192)); 273 | painter.setPen(penName); 274 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter); 275 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 276 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal)); 277 | painter.drawText(m_nameRightRect, ipAddress, optionName); 278 | } else if(m_userType == User_Type::User_Time) { // 时间 279 | QPen penText; 280 | penText.setColor(QColor(153,153,153)); 281 | painter.setPen(penText); 282 | QTextOption option(Qt::AlignCenter); 283 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 284 | QFont te_font = this->font(); 285 | te_font.setFamily("MicrosoftYaHei"); 286 | te_font.setPointSize(10); 287 | painter.setFont(te_font); 288 | painter.drawText(this->rect(),m_curTime,option); 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /Server/qnchatmessage.cpp.autosave: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------- 2 | # 3 | # Project created by QtCreator 4 | # Author: 沙振宇 5 | # CreateTime: 2018-07-23 6 | # UpdateTime: 2019-12-27 7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现 8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832 9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt 10 | # 11 | #-------------------------------------------------*/ 12 | #include "qnchatmessage.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | QNChatMessage::QNChatMessage(QWidget *parent, QString serverIP) : QWidget(parent) 23 | { 24 | QFont te_font = this->font(); 25 | te_font.setFamily("MicrosoftYaHei"); 26 | te_font.setPointSize(12); 27 | serverIPAddress = serverIP; 28 | get_local_Ip(); 29 | // te_font.setWordSpacing(0); 30 | // te_font.setLetterSpacing(QFont::PercentageSpacing,0); 31 | // te_font.setLetterSpacing(QFont::PercentageSpacing, 100); //300%,100为默认 //设置字间距% 32 | // te_font.setLetterSpacing(QFont::AbsoluteSpacing, 0); //设置字间距为3像素 //设置字间距像素值 33 | this->setFont(te_font); 34 | m_leftPixmap = QPixmap(":/img/child.png"); 35 | m_rightPixmap = QPixmap(":/img/teacher.png"); 36 | 37 | m_loadingMovie = new QMovie(this); 38 | m_loadingMovie->setFileName(":/img/loading4.gif"); 39 | m_loading = new QLabel(this); 40 | m_loading->setMovie(m_loadingMovie); 41 | m_loading->resize(16,16); 42 | m_loading->setAttribute(Qt::WA_TranslucentBackground , true); 43 | m_loading->setAutoFillBackground(false); 44 | } 45 | 46 | void QNChatMessage::get_local_Ip() 47 | { 48 | QList ipAddressesList = QNetworkInterface::allAddresses(); 49 | // use the first non-localhost IPv4 address 50 | for (int i = 0; i < ipAddressesList.size(); ++i) { 51 | qDebug()<hide(); 67 | m_loadingMovie->stop(); 68 | m_isSending = true; 69 | } 70 | 71 | void QNChatMessage::setText(QString text, QString time, QSize allSize, QNChatMessage::User_Type userType) 72 | { 73 | m_msg = text; 74 | m_userType = userType; 75 | m_time = time; 76 | m_curTime = QDateTime::fromTime_t(time.toInt()).toString("hh:mm"); 77 | m_allSize = allSize; 78 | if(userType == User_Me) { 79 | if(!m_isSending) { 80 | m_loading->move(m_kuangRightRect.x() - m_loading->width() - 10, m_kuangRightRect.y()+m_kuangRightRect.height()/2- m_loading->height()/2); 81 | m_loading->show(); 82 | m_loadingMovie->start(); 83 | } 84 | } else { 85 | m_loading->hide(); 86 | } 87 | 88 | this->update(); 89 | } 90 | 91 | QSize QNChatMessage::fontRect(QString str) 92 | { 93 | m_msg = str; 94 | int minHei = 30; 95 | int iconWH = 40; 96 | int iconSpaceW = 20; 97 | int iconRectW = 5; 98 | int iconTMPH = 10; 99 | int sanJiaoW = 6; 100 | int kuangTMP = 20; 101 | int textSpaceRect = 12; 102 | m_nameWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW); 103 | m_kuangWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW); 104 | m_textWidth = m_kuangWidth - 2 * textSpaceRect; 105 | m_spaceWid = this->width() - m_textWidth; 106 | m_iconLeftRect = QRect(iconSpaceW, iconTMPH, iconWH, iconWH); 107 | m_iconRightRect = QRect(this->width() - iconSpaceW - iconWH, iconTMPH, iconWH, iconWH); 108 | 109 | QSize size = getRealString(m_msg); // 整个的size 110 | QFontMetrics fontMetrics(QFont("Microsoft YaHei", 8, QFont::Normal)); 111 | int clientIPWidth = fontMetrics.horizontalAdvance(ipAddress); 112 | int serverIPWidth = fontMetrics.horizontalAdvance(serverIPAddress); 113 | qDebug() << "fontRect Size:" << size << clientIPWidth; 114 | int hei = size.height() < minHei ? minHei : size.height(); 115 | /*三角形*/ 116 | m_sanjiaoLeftRect = QRect(iconWH+iconSpaceW+iconRectW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight); 117 | m_sanjiaoRightRect = QRect(this->width() - iconRectW - iconWH - iconSpaceW - sanJiaoW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight); 118 | 119 | if(size.width() < (m_textWidth+m_spaceWid)) { 120 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5); 121 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth, 122 | m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5); 123 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight); 124 | m_kuangRightRect.setRect(this->width() - size.width() + m_spaceWid - 2*textSpaceRect - iconWH - iconSpaceW - iconRectW - sanJiaoW, 125 | m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight); 126 | } else { 127 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5); 128 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth, m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5); 129 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight); 130 | m_kuangRightRect.setRect(iconWH + kuangTMP + iconSpaceW + iconRectW - sanJiaoW, m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight); 131 | } 132 | /*消息框*/ 133 | m_textLeftRect.setRect(m_kuangLeftRect.x()+textSpaceRect,m_kuangLeftRect.y()+iconTMPH, 134 | m_kuangLeftRect.width()-2*textSpaceRect,m_kuangLeftRect.height()-2*iconTMPH); 135 | m_textRightRect.setRect(m_kuangRightRect.x()+textSpaceRect,m_kuangRightRect.y()+iconTMPH, 136 | m_kuangRightRect.width()-2*textSpaceRect,m_kuangRightRect.height()-2*iconTMPH); 137 | 138 | return QSize(size.width(), hei); 139 | } 140 | 141 | QSize QNChatMessage::getRealString(QString src) 142 | { 143 | QFontMetricsF fm(this->font()); 144 | m_lineHeight = fm.lineSpacing(); 145 | int nCount = src.count("\n"); 146 | int nMaxWidth = 0; 147 | if(nCount == 0) { 148 | nMaxWidth = qCeil(fm.width(src)); 149 | QString value = src; 150 | if(nMaxWidth > m_textWidth) { 151 | qDebug() << "2222"; 152 | nMaxWidth = m_textWidth; 153 | int size = m_textWidth / fm.width(" "); 154 | int num = fm.width(value) / m_textWidth; 155 | num = ( fm.width(value) ) / m_textWidth; 156 | nCount += num; 157 | QString temp = ""; 158 | for(int i = 0; i < num; i++) { 159 | temp += value.mid(i*size, (i+1)*size) + "\n"; 160 | } 161 | src.replace(value, temp); 162 | } 163 | } else { 164 | for(int i = 0; i < (nCount + 1); i++) { 165 | QString value = src.split("\n").at(i); 166 | nMaxWidth = qCeil(fm.width(value)) > nMaxWidth ? qCeil(fm.width(value)) : nMaxWidth; 167 | if(fm.width(value) > m_textWidth) { 168 | nMaxWidth = m_textWidth; 169 | int size = m_textWidth / fm.width(" "); 170 | int num = fm.width(value) / m_textWidth; 171 | num = ((i+num)*fm.width(" ") + fm.width(value)) / m_textWidth; 172 | nCount += num; 173 | QString temp = ""; 174 | for(int i = 0; i < num; i++) { 175 | temp += value.mid(i*size, (i+1)*size) + "\n"; 176 | } 177 | src.replace(value, temp); 178 | } 179 | } 180 | } 181 | return QSize(nMaxWidth+m_spaceWid, (nCount + 1) * m_lineHeight+2*m_lineHeight); 182 | } 183 | 184 | void QNChatMessage::paintEvent(QPaintEvent *event) 185 | { 186 | Q_UNUSED(event); 187 | 188 | QPainter painter(this); 189 | painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿 190 | painter.setPen(Qt::NoPen); 191 | painter.setBrush(QBrush(Qt::gray)); 192 | 193 | if(m_userType == User_Type::User_Consumer) { // 用户 194 | //头像 195 | // painter.drawRoundedRect(m_iconLeftRect,m_iconLeftRect.width(),m_iconLeftRect.height()); 196 | painter.drawPixmap(m_iconLeftRect, m_leftPixmap); 197 | 198 | //框加边 199 | QColor col_KuangB(234, 234, 234); 200 | painter.setBrush(QBrush(col_KuangB)); 201 | painter.drawRoundedRect(m_kuangLeftRect.x()-1,m_kuangLeftRect.y()-1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4); 202 | //框 203 | QColor col_Kuang(255,255,255); 204 | painter.setBrush(QBrush(col_Kuang)); 205 | painter.drawRoundedRect(m_kuangLeftRect,4,4); 206 | 207 | //三角 208 | QPointF points[3] = { 209 | QPointF(m_sanjiaoLeftRect.x(), 30), 210 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 25), 211 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 35), 212 | }; 213 | QPen pen; 214 | pen.setColor(col_Kuang); 215 | painter.setPen(pen); 216 | painter.drawPolygon(points, 3); 217 | 218 | //三角加边 219 | QPen penSanJiaoBian; 220 | penSanJiaoBian.setColor(col_KuangB); 221 | painter.setPen(penSanJiaoBian); 222 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 24)); 223 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 36)); 224 | 225 | //内容 226 | QPen penText; 227 | penText.setColor(QColor(51,51,51)); 228 | painter.setPen(penText); 229 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter); 230 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 231 | painter.setFont(this->font()); 232 | painter.drawText(m_textLeftRect, m_msg,option); 233 | 234 | QPen penName; 235 | penName.setColor(QColor(192,192,192)); 236 | painter.setPen(penName); 237 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter); 238 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 239 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal)); 240 | painter.drawText(m_nameLeftRect, serverIPAddress, optionName); 241 | } else if(m_userType == User_Type::User_Me) { // 自己 242 | //头像 243 | // painter.drawRoundedRect(m_iconRightRect,m_iconRightRect.width(),m_iconRightRect.height()); 244 | painter.drawPixmap(m_iconRightRect, m_rightPixmap); 245 | 246 | //框 247 | QColor col_Kuang(75,164,242); 248 | painter.setBrush(QBrush(col_Kuang)); 249 | painter.drawRoundedRect(m_kuangRightRect,4,4); 250 | 251 | //三角 252 | QPointF points[3] = { 253 | QPointF(m_sanjiaoRightRect.x()+m_sanjiaoRightRect.width(), 30), 254 | QPointF(m_sanjiaoRightRect.x(), 25), 255 | QPointF(m_sanjiaoRightRect.x(), 35), 256 | }; 257 | QPen pen; 258 | pen.setColor(col_Kuang); 259 | painter.setPen(pen); 260 | painter.drawPolygon(points, 3); 261 | 262 | //内容 263 | QPen penText; 264 | penText.setColor(Qt::white); 265 | painter.setPen(penText); 266 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter); 267 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 268 | painter.setFont(this->font()); 269 | painter.drawText(m_textRightRect,m_msg,option); 270 | 271 | QPen penName; 272 | penName.setColor(QColor(192,192,192)); 273 | painter.setPen(penName); 274 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter); 275 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 276 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal)); 277 | painter.drawText(m_nameRightRect, ipAddress, optionName); 278 | } else if(m_userType == User_Type::User_Time) { // 时间 279 | QPen penText; 280 | penText.setColor(QColor(153,153,153)); 281 | painter.setPen(penText); 282 | QTextOption option(Qt::AlignCenter); 283 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 284 | QFont te_font = this->font(); 285 | te_font.setFamily("MicrosoftYaHei"); 286 | te_font.setPointSize(10); 287 | painter.setFont(te_font); 288 | painter.drawText(this->rect(),m_curTime,option); 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /Server/qnchatmessage.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------- 2 | # 3 | # Project created by QtCreator 4 | # Author: 沙振宇 5 | # CreateTime: 2018-07-23 6 | # UpdateTime: 2019-12-27 7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现 8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832 9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt 10 | # 11 | #-------------------------------------------------*/ 12 | #ifndef QNCHATMESSAGE_H 13 | #define QNCHATMESSAGE_H 14 | 15 | #include 16 | 17 | class QPaintEvent; 18 | class QPainter; 19 | class QLabel; 20 | class QMovie; 21 | 22 | class QNChatMessage : public QWidget 23 | { 24 | Q_OBJECT 25 | public: 26 | explicit QNChatMessage(QWidget *parent = nullptr, QString serverIP = "127.0.0.1"); 27 | 28 | enum User_Type{ 29 | User_System,//系统 30 | User_Me, //自己 31 | User_She, //用户 32 | User_Time, //时间 33 | }; 34 | void setTextSuccess(); 35 | void setText(QString text, QString time, QSize allSize, User_Type userType); 36 | 37 | QSize getRealString(QString src); 38 | QSize fontRect(QString str); 39 | 40 | inline QString text() {return m_msg;} 41 | inline QString time() {return m_time;} 42 | inline User_Type userType() {return m_userType;} 43 | void get_local_Ip(); 44 | protected: 45 | void paintEvent(QPaintEvent *event); 46 | private: 47 | QString m_msg; 48 | QString m_time; 49 | QString m_curTime; 50 | QString ipAddress; //本机IP地址 51 | QString serverIPAddress; 52 | QSize m_allSize; 53 | User_Type m_userType = User_System; 54 | 55 | int m_nameWidth; 56 | int m_kuangWidth; 57 | int m_textWidth; 58 | int m_spaceWid; 59 | int m_lineHeight; 60 | 61 | QRect m_iconLeftRect; 62 | QRect m_iconRightRect; 63 | QRect m_sanjiaoLeftRect; 64 | QRect m_sanjiaoRightRect; 65 | QRect m_nameLeftRect; 66 | QRect m_nameRightRect; 67 | QRect m_kuangLeftRect; 68 | QRect m_kuangRightRect; 69 | QRect m_textLeftRect; 70 | QRect m_textRightRect; 71 | QPixmap m_leftPixmap; 72 | QPixmap m_rightPixmap; 73 | QLabel* m_loading = Q_NULLPTR; 74 | QMovie* m_loadingMovie = Q_NULLPTR; 75 | bool m_isSending = false; 76 | }; 77 | 78 | #endif // QNCHATMESSAGE_H 79 | -------------------------------------------------------------------------------- /Server/qnchatmessage.h.autosave: -------------------------------------------------------------------------------- 1 | #ifndef QNCHATMESSAGE_H 2 | #define QNCHATMESSAGE_H 3 | 4 | #include 5 | 6 | class QPaintEvent; 7 | class QPainter; 8 | class QLabel; 9 | class QMovie; 10 | 11 | class QNChatMessage : public QWidget 12 | { 13 | Q_OBJECT 14 | public: 15 | explicit QNChatMessage(QWidget *parent = nullptr, QString serverIP = "127.0.0.1"); 16 | 17 | enum User_Type{ 18 | User_System,//系统 19 | User_Me, //自己 20 | User_Consumer, //用户 21 | User_Time, //时间 22 | }; 23 | void setTextSuccess(); 24 | void setText(QString text, QString time, QSize allSize, User_Type userType); 25 | 26 | QSize getRealString(QString src); 27 | QSize fontRect(QString str); 28 | 29 | inline QString text() {return m_msg;} 30 | inline QString time() {return m_time;} 31 | inline User_Type userType() {return m_userType;} 32 | void get_local_Ip(); 33 | protected: 34 | void paintEvent(QPaintEvent *event); 35 | private: 36 | QString m_msg; 37 | QString m_time; 38 | QString m_curTime; 39 | QString ipAddress; //本机IP地址 40 | QString serverIPAddress; 41 | QSize m_allSize; 42 | User_Type m_userType = User_System; 43 | 44 | int m_nameWidth; 45 | int m_kuangWidth; 46 | int m_textWidth; 47 | int m_spaceWid; 48 | int m_lineHeight; 49 | 50 | QRect m_iconLeftRect; 51 | QRect m_iconRightRect; 52 | QRect m_sanjiaoLeftRect; 53 | QRect m_sanjiaoRightRect; 54 | QRect m_nameLeftRect; 55 | QRect m_nameRightRect; 56 | QRect m_kuangLeftRect; 57 | QRect m_kuangRightRect; 58 | QRect m_textLeftRect; 59 | QRect m_textRightRect; 60 | QPixmap m_leftPixmap; 61 | QPixmap m_rightPixmap; 62 | QLabel* m_loading = Q_NULLPTR; 63 | QMovie* m_loadingMovie = Q_NULLPTR; 64 | bool m_isSending = false; 65 | }; 66 | 67 | #endif // QNCHATMESSAGE_H 68 | -------------------------------------------------------------------------------- /Server/widget.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include "clientaddress.h" 3 | #include "ui_widget.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | //#include "seekfile.h" 17 | 18 | Widget::Widget(QWidget *parent) : 19 | QWidget(parent), 20 | ui(new Ui::Widget) 21 | { 22 | ui->setupUi(this); 23 | setWindowTitle(tr("局域网文件传输服务器")); 24 | /*清空列表文件*/ 25 | if((fp = fopen("/home/leo/Desktop/NetworkFileTransfer-master/FileList/FILELIST.txt","w+"))==NULL) 26 | { 27 | qDebug()<<"Clear FILELIST.TXT error!"; 28 | } 29 | fclose(fp); 30 | server = new Myserver(this); 31 | server->listen(QHostAddress::Any, 8888); 32 | closeCommand = 0; 33 | ui->textEdit->document()->setMaximumBlockCount(100); 34 | // ui->ClientPB1->setEnabled(false); 35 | // ui->ClientPB2->setEnabled(false); 36 | // ui->ClientPB3->setEnabled(false); 37 | // /*为三个按键安装事件过滤器*/ 38 | // ui->ClientPB1->installEventFilter(this); 39 | // ui->ClientPB2->installEventFilter(this); 40 | // ui->ClientPB3->installEventFilter(this); 41 | 42 | // ui->LBstate1->setText(tr("断开")); 43 | // ui->LBstate2->setText(tr("断开")); 44 | // ui->LBstate3->setText(tr("断开")); 45 | 46 | ui->pushButton->setEnabled(false); 47 | 48 | connect(ui->pushButton,&QPushButton::clicked,this,&Widget::fileTranferButtonSlot); 49 | connect(ui->AddFilePB,&QPushButton::clicked,this,&Widget::addFilePBSlot); 50 | // connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFileListItem); 51 | connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFile); 52 | /*服务器端主动断开连接*/ 53 | connect(this,&Widget::clientDiconnectSignal,server, &Myserver::clientDisconnectSlot); 54 | connect(ui->InfoPushButton,&QPushButton::clicked,this,&Widget::infoTranferButtonSlot); 55 | connect(ui->DelInfoPB,&QPushButton::clicked,this,&Widget::deleteInfo); 56 | // connect(ui->listWidget,&QAbstractItemView::doubleClicked,this,&Widget::doubleClickedItem); 57 | } 58 | 59 | Widget::~Widget() 60 | { 61 | delete ui; 62 | } 63 | 64 | void Widget::dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type) 65 | { 66 | messageW->setFixedWidth(ui->listWidget->width()-10); 67 | QSize size = messageW->fontRect(text); 68 | item->setSizeHint(size); 69 | messageW->setText(text, time, size, type); 70 | ui->listWidget->setItemWidget(item, messageW); 71 | } 72 | 73 | void Widget::dealMessageTime(QString curMsgTime) 74 | { 75 | bool isShowTime = false; 76 | if(ui->listWidget->count() > 0) { 77 | QListWidgetItem* lastItem = ui->listWidget->item(ui->listWidget->count() - 1); 78 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(lastItem); 79 | int lastTime = messageW->time().toInt(); 80 | int curTime = curMsgTime.toInt(); 81 | qDebug() << "curTime lastTime:" << curTime - lastTime; 82 | isShowTime = ((curTime - lastTime) > 60); // 两个消息相差一分钟 83 | // isShowTime = true; 84 | } else { 85 | isShowTime = true; 86 | } 87 | if(isShowTime) { 88 | QNChatMessage* messageTime = new QNChatMessage(ui->listWidget->parentWidget()); 89 | QListWidgetItem* itemTime = new QListWidgetItem(ui->listWidget); 90 | 91 | QSize size = QSize(ui->listWidget->width()-10, 40); 92 | messageTime->resize(size); 93 | itemTime->setSizeHint(size); 94 | messageTime->setText(curMsgTime, curMsgTime, size, QNChatMessage::User_Time); 95 | ui->listWidget->setItemWidget(itemTime, messageTime); 96 | } 97 | } 98 | 99 | void Widget::resizeEvent(QResizeEvent *event) 100 | { 101 | Q_UNUSED(event); 102 | 103 | for(int i = 0; i < ui->listWidget->count(); i++) { 104 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i)); 105 | QListWidgetItem* item = ui->listWidget->item(i); 106 | 107 | dealMessage(messageW, item, messageW->text(), messageW->time(), messageW->userType()); 108 | } 109 | } 110 | 111 | void Widget::closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time) 112 | { 113 | /*判断是哪个客户端断开,并做相应的清除工作*/ 114 | qDebug() << "#"; 115 | for(int i = 0; i < IPOrder.size(); i++) 116 | { 117 | qDebug() << IPOrder.at(i) << " "; 118 | } 119 | qDebug() << index << " "; 120 | qDebug() << clientIp << " "; 121 | closeFlag_current *= -1; 122 | int deleteIndex = IPOrder.indexOf(clientIp); 123 | // qDebug() << QString::number(deleteIndex); 124 | QListWidgetItem *item = ui->clientListWidget->takeItem(deleteIndex); 125 | delete item; 126 | IPOrder.remove(deleteIndex); 127 | index--; 128 | // QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss"); 129 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 130 | // ui->textEdit->append(current_date + " —— IP: " + clientIp + " 断开连接"); 131 | if(closeFlag_previous * closeFlag_current == -1) 132 | { 133 | QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss"); 134 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 135 | ui->textEdit->append(current_date + " —— IP: " + clientIp + " Port: " + QString::number(clientPort) + " 客户端断开连接"); 136 | } 137 | server->socketNum--; 138 | closeFlag_previous = closeFlag_current; 139 | } 140 | 141 | void Widget::addFilePBSlot() 142 | { 143 | /*打开目录获得文件目录*/ 144 | // dirPath = QFileDialog::getExistingDirectory(this,0,"./"); 145 | dirPath = QFileDialog::getOpenFileName(this, "选择文件", "./", "(*.*)"); 146 | QDir dir(dirPath); 147 | if(dirPath.isEmpty()) 148 | return; 149 | ui->lineEdit->setText(dirPath); 150 | ui->pushButton->setEnabled(true); 151 | } 152 | void Widget::getSendFileList(QString path) 153 | { 154 | // FILE *fp; 155 | // /*已追加的方式打开文件*/ 156 | // fp = fopen("./FileList/FILELIST.TXT","at+"); 157 | // if(fp == NULL) 158 | // { 159 | // qDebug()<<"Open FILELIST.TXT failed!"; 160 | // return; 161 | // } 162 | QFile filelist("./FileList/FILELIST.TXT"); 163 | QTextStream out(&filelist); 164 | if(!filelist.open(QFile::WriteOnly|QFile::Text)) 165 | { 166 | qDebug()<<"write FILELIST.TXT error!"<lineEdit->setText(""); 236 | ui->pushButton->setEnabled(false); 237 | } 238 | 239 | void Widget::deleteInfo() 240 | { 241 | info.clear(); 242 | ui->textEdit_2->setText(""); 243 | } 244 | 245 | //void Widget::deleteFileListItem() 246 | //{ 247 | // /*获得当前选中项,并删除*/ 248 | // QListWidgetItem *item = ui->listWidget->currentItem(); 249 | // delete item; 250 | //} 251 | 252 | //void Widget::doubleClickedItem() 253 | //{ 254 | // /*获得双击项文本*/ 255 | // QString str = ui->listWidget->currentItem()->text(); 256 | //#if defined __DEBUG__ 257 | // qDebug()<<"双击项文本内容str为"<getSendFileList(dirPath); 270 | //// fp = fopen("./FileList/FILELIST.TXT","ab"); 271 | //// if(fp == NULL) 272 | //// { 273 | //// qDebug()<<"Open FILELIST.TXT failed!"; 274 | //// return; 275 | //// } 276 | //// this->DfsFolder(dirPath.toStdString(),0); 277 | //// fclose(fp); 278 | // QStringList nameFilters; 279 | // nameFilters << "*"; 280 | // QFileInfoList files = dir.entryInfoList(nameFilters,QDir::AllEntries,QDir::DirsFirst); 281 | // ui->listWidget->clear(); 282 | // if(str=="..") //当返回上一级目录时,只显示目录不显示文件 283 | // { 284 | // for(int i =0 ;ilistWidget->addItem(tmp); 292 | // } 293 | // } 294 | // } 295 | // else 296 | // { 297 | // for(int i =0 ;ilistWidget->addItem(tmp); 305 | // } 306 | // if(tmpFileInfo.isFile()) //显示文件 307 | // { 308 | // ui->listWidget->addItem(tmp); 309 | // } 310 | // } 311 | // } 312 | //} 313 | 314 | void Widget::fileTranferButtonSlot() 315 | { 316 | // QString fileName = QFileDialog::getOpenFileName(this); 317 | //#if defined __DEBUG__ 318 | // qDebug()<<"Open file's name is"<socketNum > 0) 326 | { 327 | emit sendFileWidgetSignal(dirPath); 328 | } 329 | else 330 | { 331 | ui->textEdit->append("当前无客户端连接,传输文件无效!"); 332 | } 333 | } 334 | 335 | void Widget::infoTranferButtonSlot() 336 | { 337 | info = ui->textEdit_2->toPlainText(); 338 | qDebug() << info; 339 | if(info.size() > 0) 340 | { 341 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳 342 | qDebug()<<"addMessage" << info << time << ui->listWidget->count(); 343 | dealMessageTime(time); 344 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ipAddress); 345 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 346 | dealMessage(messageW, item, info, time, QNChatMessage::User_Me); 347 | // else { 348 | // if(clientInfo != "") { 349 | // dealMessageTime(time); 350 | 351 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget()); 352 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 353 | // dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_She); 354 | // } 355 | // } 356 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1); 357 | emit sendInfoWidgetSignal(info); 358 | } 359 | else 360 | { 361 | ui->textEdit->append("无消息输入,传输消息无效!"); 362 | } 363 | } 364 | 365 | //void Widget::addClientIPTGUISlot(QString CIP,int CPort, int ID,int state) 366 | //{ 367 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 368 | // if((ID == 1)&&(state==QAbstractSocket::ConnectedState)) 369 | // { 370 | // ui->LBDisplayIP1->setText(CIP); 371 | // ui->LBDisplayPort1->setText(QString::number(CPort)); 372 | // ui->LBstate1->setText(tr("连接")); 373 | // ui->ClientPB1->setEnabled(true); 374 | // } 375 | // else if((ID == 2)&&(state==QAbstractSocket::ConnectedState)) 376 | // { 377 | // ui->LBDisplayIP2->setText(CIP); 378 | // ui->LBDisplayPort2->setText(QString::number(CPort)); 379 | // ui->LBstate2->setText(tr("连接")); 380 | // ui->ClientPB2->setEnabled(true); 381 | // } 382 | // else if((ID == 3)&&(state==QAbstractSocket::ConnectedState)) 383 | // { 384 | // ui->LBDisplayIP3->setText(CIP); 385 | // ui->LBDisplayPort3->setText(QString::number(CPort)); 386 | // ui->LBstate3->setText(tr("连接")); 387 | // ui->ClientPB3->setEnabled(true); 388 | // } 389 | //} 390 | 391 | void Widget::displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time) 392 | { 393 | QString current_date = current_time.toString("yyyy.MM.dd hh:mm:ss"); 394 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 395 | if(state==QAbstractSocket::ConnectedState) 396 | { 397 | ui->textEdit->append(current_date + " —— IP: " + CIP + " Port: " + QString::number(CPort) + " 客户端成功连接"); 398 | } 399 | IPOrder.append(CIP); 400 | index++; 401 | QListWidgetItem * item = new QListWidgetItem(ui->clientListWidget); 402 | QSize size = item->sizeHint(); 403 | item->setSizeHint(QSize(300, 50)); 404 | ui->clientListWidget->addItem(item); 405 | clientAddress * client = new clientAddress(CIP, CPort); 406 | client->setParent(ui->clientListWidget); 407 | client->setSizeIncrement(size.width(), 56); 408 | ui->clientListWidget->setItemWidget(item, client); 409 | connect(client, &clientAddress::clientAddressSignal, this, &Widget::clientAddressSlot); 410 | } 411 | 412 | void Widget::clientAddressSlot(QString IP, int clientPort) 413 | { 414 | int deleteIndex = IPOrder.indexOf(IP); 415 | closeFlag_current *= -1; 416 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 417 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 418 | ui->textEdit->append(current_date + " —— IP: " + IP + " Port: " + QString::number(clientPort) + " 服务器断开连接"); 419 | emit clientAddressWidgetSignal(deleteIndex); 420 | } 421 | 422 | void Widget::sendStateDisplaySlot(QString msg, QString info) 423 | { 424 | if(msg == "服务器开始发送消息") 425 | { 426 | /*消息框*/ 427 | // QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳 428 | // qDebug()<<"addMessage" << info << time << ui->listWidget->count(); 429 | // dealMessageTime(time); 430 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), IPAddress); 431 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 432 | // dealMessage(messageW, item, info, time, QNChatMessage::User_Me); 433 | //// else { 434 | //// if(clientInfo != "") { 435 | //// dealMessageTime(time); 436 | 437 | //// QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget()); 438 | //// QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 439 | //// dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_She); 440 | //// } 441 | //// } 442 | // ui->listWidget->setCurrentRow(ui->listWidget->count()-1); 443 | } 444 | else if(msg == "服务器发送消息成功") 445 | { 446 | qDebug() << "6666666"; 447 | /*暂停发送消息状态*/ 448 | qDebug() << ui->listWidget->count(); 449 | qDebug() << info; 450 | for(int i = ui->listWidget->count() - 1; i > 0; i--) { 451 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i)); 452 | if(messageW->text() == info) { 453 | qDebug() << "7777777"; 454 | messageW->setTextSuccess(); 455 | } 456 | } 457 | 458 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 459 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 460 | ui->textEdit->append(current_date + " —— " + msg); 461 | } 462 | else 463 | { 464 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 465 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 466 | ui->textEdit->append(current_date + " —— " + msg); 467 | } 468 | } 469 | 470 | void Widget::sendInfoDisplaySlot(QString clientInfo, QString ip) 471 | { 472 | 473 | /*消息框*/ 474 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳 475 | qDebug()<<"addMessage" << clientInfo << time << ui->listWidget->count(); 476 | if(clientInfo != "") { 477 | dealMessageTime(time); 478 | 479 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ip); 480 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 481 | dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_She); 482 | } 483 | 484 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1); 485 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 486 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 487 | ui->textEdit->append(current_date + " —— " + "服务器接收消息成功"); 488 | // QMessageBox::about(NULL, "客户端消息", clientInfo); 489 | } 490 | 491 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/ 492 | //void Widget::DfsFolder(std::string path,int layer) 493 | //{ 494 | // _finddata_t file_info; 495 | // std::string current_path=path+"/*.*"; //也可以用/*来匹配所有 496 | // int handle=_findfirst(current_path.c_str(),&file_info); 497 | // /*返回值为-1则查找失败*/ 498 | // if(-1==handle) 499 | // { 500 | // std::cout<<"cannot match the path"< 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | //#include "seekfile.h" 17 | 18 | Widget::Widget(QWidget *parent) : 19 | QWidget(parent), 20 | ui(new Ui::Widget) 21 | { 22 | ui->setupUi(this); 23 | setWindowTitle(tr("局域网文件传输服务器")); 24 | /*清空列表文件*/ 25 | if((fp = fopen("/home/leo/Desktop/NetworkFileTransfer-master/FileList/FILELIST.txt","w+"))==NULL) 26 | { 27 | qDebug()<<"Clear FILELIST.TXT error!"; 28 | } 29 | fclose(fp); 30 | server = new Myserver(this); 31 | server->listen(QHostAddress::Any, 8888); 32 | closeCommand = 0; 33 | ui->textEdit->document()->setMaximumBlockCount(100); 34 | // ui->ClientPB1->setEnabled(false); 35 | // ui->ClientPB2->setEnabled(false); 36 | // ui->ClientPB3->setEnabled(false); 37 | // /*为三个按键安装事件过滤器*/ 38 | // ui->ClientPB1->installEventFilter(this); 39 | // ui->ClientPB2->installEventFilter(this); 40 | // ui->ClientPB3->installEventFilter(this); 41 | 42 | // ui->LBstate1->setText(tr("断开")); 43 | // ui->LBstate2->setText(tr("断开")); 44 | // ui->LBstate3->setText(tr("断开")); 45 | 46 | ui->pushButton->setEnabled(false); 47 | 48 | connect(ui->pushButton,&QPushButton::clicked,this,&Widget::fileTranferButtonSlot); 49 | connect(ui->AddFilePB,&QPushButton::clicked,this,&Widget::addFilePBSlot); 50 | // connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFileListItem); 51 | connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFile); 52 | /*服务器端主动断开连接*/ 53 | connect(this,&Widget::clientDiconnectSignal,server, &Myserver::clientDisconnectSlot); 54 | connect(ui->InfoPushButton,&QPushButton::clicked,this,&Widget::infoTranferButtonSlot); 55 | connect(ui->DelInfoPB,&QPushButton::clicked,this,&Widget::deleteInfo); 56 | // connect(ui->listWidget,&QAbstractItemView::doubleClicked,this,&Widget::doubleClickedItem); 57 | } 58 | 59 | Widget::~Widget() 60 | { 61 | delete ui; 62 | } 63 | 64 | void Widget::dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type) 65 | { 66 | messageW->setFixedWidth(ui->listWidget->width()-10); 67 | QSize size = messageW->fontRect(text); 68 | item->setSizeHint(size); 69 | messageW->setText(text, time, size, type); 70 | ui->listWidget->setItemWidget(item, messageW); 71 | } 72 | 73 | void Widget::dealMessageTime(QString curMsgTime) 74 | { 75 | bool isShowTime = false; 76 | if(ui->listWidget->count() > 0) { 77 | QListWidgetItem* lastItem = ui->listWidget->item(ui->listWidget->count() - 1); 78 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(lastItem); 79 | int lastTime = messageW->time().toInt(); 80 | int curTime = curMsgTime.toInt(); 81 | qDebug() << "curTime lastTime:" << curTime - lastTime; 82 | isShowTime = ((curTime - lastTime) > 60); // 两个消息相差一分钟 83 | // isShowTime = true; 84 | } else { 85 | isShowTime = true; 86 | } 87 | if(isShowTime) { 88 | QNChatMessage* messageTime = new QNChatMessage(ui->listWidget->parentWidget()); 89 | QListWidgetItem* itemTime = new QListWidgetItem(ui->listWidget); 90 | 91 | QSize size = QSize(ui->listWidget->width()-10, 40); 92 | messageTime->resize(size); 93 | itemTime->setSizeHint(size); 94 | messageTime->setText(curMsgTime, curMsgTime, size, QNChatMessage::User_Time); 95 | ui->listWidget->setItemWidget(itemTime, messageTime); 96 | } 97 | } 98 | 99 | void Widget::resizeEvent(QResizeEvent *event) 100 | { 101 | Q_UNUSED(event); 102 | 103 | for(int i = 0; i < ui->listWidget->count(); i++) { 104 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i)); 105 | QListWidgetItem* item = ui->listWidget->item(i); 106 | 107 | dealMessage(messageW, item, messageW->text(), messageW->time(), messageW->userType()); 108 | } 109 | } 110 | 111 | void Widget::closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time) 112 | { 113 | /*判断是哪个客户端断开,并做相应的清除工作*/ 114 | qDebug() << "#"; 115 | for(int i = 0; i < IPOrder.size(); i++) 116 | { 117 | qDebug() << IPOrder.at(i) << " "; 118 | } 119 | qDebug() << index << " "; 120 | qDebug() << clientIp << " "; 121 | closeFlag_current *= -1; 122 | int deleteIndex = IPOrder.indexOf(clientIp); 123 | // qDebug() << QString::number(deleteIndex); 124 | QListWidgetItem *item = ui->clientListWidget->takeItem(deleteIndex); 125 | delete item; 126 | IPOrder.remove(deleteIndex); 127 | index--; 128 | // QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss"); 129 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 130 | // ui->textEdit->append(current_date + " —— IP: " + clientIp + " 断开连接"); 131 | if(closeFlag_previous * closeFlag_current == -1) 132 | { 133 | QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss"); 134 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 135 | ui->textEdit->append(current_date + " —— IP: " + clientIp + " Port: " + QString::number(clientPort) + " 客户端断开连接"); 136 | } 137 | server->socketNum--; 138 | closeFlag_previous = closeFlag_current; 139 | } 140 | 141 | void Widget::addFilePBSlot() 142 | { 143 | /*打开目录获得文件目录*/ 144 | // dirPath = QFileDialog::getExistingDirectory(this,0,"./"); 145 | dirPath = QFileDialog::getOpenFileName(this, "选择文件", "./", "(*.*)"); 146 | QDir dir(dirPath); 147 | if(dirPath.isEmpty()) 148 | return; 149 | ui->lineEdit->setText(dirPath); 150 | ui->pushButton->setEnabled(true); 151 | } 152 | void Widget::getSendFileList(QString path) 153 | { 154 | // FILE *fp; 155 | // /*已追加的方式打开文件*/ 156 | // fp = fopen("./FileList/FILELIST.TXT","at+"); 157 | // if(fp == NULL) 158 | // { 159 | // qDebug()<<"Open FILELIST.TXT failed!"; 160 | // return; 161 | // } 162 | QFile filelist("./FileList/FILELIST.TXT"); 163 | QTextStream out(&filelist); 164 | if(!filelist.open(QFile::WriteOnly|QFile::Text)) 165 | { 166 | qDebug()<<"write FILELIST.TXT error!"<lineEdit->setText(""); 236 | ui->pushButton->setEnabled(false); 237 | } 238 | 239 | void Widget::deleteInfo() 240 | { 241 | info.clear(); 242 | ui->textEdit_2->setText(""); 243 | } 244 | 245 | //void Widget::deleteFileListItem() 246 | //{ 247 | // /*获得当前选中项,并删除*/ 248 | // QListWidgetItem *item = ui->listWidget->currentItem(); 249 | // delete item; 250 | //} 251 | 252 | //void Widget::doubleClickedItem() 253 | //{ 254 | // /*获得双击项文本*/ 255 | // QString str = ui->listWidget->currentItem()->text(); 256 | //#if defined __DEBUG__ 257 | // qDebug()<<"双击项文本内容str为"<getSendFileList(dirPath); 270 | //// fp = fopen("./FileList/FILELIST.TXT","ab"); 271 | //// if(fp == NULL) 272 | //// { 273 | //// qDebug()<<"Open FILELIST.TXT failed!"; 274 | //// return; 275 | //// } 276 | //// this->DfsFolder(dirPath.toStdString(),0); 277 | //// fclose(fp); 278 | // QStringList nameFilters; 279 | // nameFilters << "*"; 280 | // QFileInfoList files = dir.entryInfoList(nameFilters,QDir::AllEntries,QDir::DirsFirst); 281 | // ui->listWidget->clear(); 282 | // if(str=="..") //当返回上一级目录时,只显示目录不显示文件 283 | // { 284 | // for(int i =0 ;ilistWidget->addItem(tmp); 292 | // } 293 | // } 294 | // } 295 | // else 296 | // { 297 | // for(int i =0 ;ilistWidget->addItem(tmp); 305 | // } 306 | // if(tmpFileInfo.isFile()) //显示文件 307 | // { 308 | // ui->listWidget->addItem(tmp); 309 | // } 310 | // } 311 | // } 312 | //} 313 | 314 | void Widget::fileTranferButtonSlot() 315 | { 316 | // QString fileName = QFileDialog::getOpenFileName(this); 317 | //#if defined __DEBUG__ 318 | // qDebug()<<"Open file's name is"<socketNum > 0) 326 | { 327 | emit sendFileWidgetSignal(dirPath); 328 | } 329 | else 330 | { 331 | ui->textEdit->append("当前无客户端连接,传输文件无效!"); 332 | } 333 | } 334 | 335 | void Widget::infoTranferButtonSlot() 336 | { 337 | info = ui->textEdit_2->toPlainText(); 338 | qDebug() << info; 339 | if(info.size() > 0) 340 | { 341 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳 342 | qDebug()<<"addMessage" << info << time << ui->listWidget->count(); 343 | dealMessageTime(time); 344 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ipAddress); 345 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 346 | dealMessage(messageW, item, info, time, QNChatMessage::User_Me); 347 | // else { 348 | // if(clientInfo != "") { 349 | // dealMessageTime(time); 350 | 351 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget()); 352 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 353 | // dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_Consumer); 354 | // } 355 | // } 356 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1); 357 | emit sendInfoWidgetSignal(info); 358 | } 359 | else 360 | { 361 | ui->textEdit->append("无消息输入,传输消息无效!"); 362 | } 363 | } 364 | 365 | //void Widget::addClientIPTGUISlot(QString CIP,int CPort, int ID,int state) 366 | //{ 367 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 368 | // if((ID == 1)&&(state==QAbstractSocket::ConnectedState)) 369 | // { 370 | // ui->LBDisplayIP1->setText(CIP); 371 | // ui->LBDisplayPort1->setText(QString::number(CPort)); 372 | // ui->LBstate1->setText(tr("连接")); 373 | // ui->ClientPB1->setEnabled(true); 374 | // } 375 | // else if((ID == 2)&&(state==QAbstractSocket::ConnectedState)) 376 | // { 377 | // ui->LBDisplayIP2->setText(CIP); 378 | // ui->LBDisplayPort2->setText(QString::number(CPort)); 379 | // ui->LBstate2->setText(tr("连接")); 380 | // ui->ClientPB2->setEnabled(true); 381 | // } 382 | // else if((ID == 3)&&(state==QAbstractSocket::ConnectedState)) 383 | // { 384 | // ui->LBDisplayIP3->setText(CIP); 385 | // ui->LBDisplayPort3->setText(QString::number(CPort)); 386 | // ui->LBstate3->setText(tr("连接")); 387 | // ui->ClientPB3->setEnabled(true); 388 | // } 389 | //} 390 | 391 | void Widget::displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time) 392 | { 393 | QString current_date = current_time.toString("yyyy.MM.dd hh:mm:ss"); 394 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 395 | if(state==QAbstractSocket::ConnectedState) 396 | { 397 | ui->textEdit->append(current_date + " —— IP: " + CIP + " Port: " + QString::number(CPort) + " 客户端成功连接"); 398 | } 399 | IPOrder.append(CIP); 400 | index++; 401 | QListWidgetItem * item = new QListWidgetItem(ui->clientListWidget); 402 | QSize size = item->sizeHint(); 403 | item->setSizeHint(QSize(300, 50)); 404 | ui->clientListWidget->addItem(item); 405 | clientAddress * client = new clientAddress(CIP, CPort); 406 | client->setParent(ui->clientListWidget); 407 | client->setSizeIncrement(size.width(), 56); 408 | ui->clientListWidget->setItemWidget(item, client); 409 | connect(client, &clientAddress::clientAddressSignal, this, &Widget::clientAddressSlot); 410 | } 411 | 412 | void Widget::clientAddressSlot(QString IP, int clientPort) 413 | { 414 | int deleteIndex = IPOrder.indexOf(IP); 415 | closeFlag_current *= -1; 416 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 417 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 418 | ui->textEdit->append(current_date + " —— IP: " + IP + " Port: " + QString::number(clientPort) + " 服务器断开连接"); 419 | emit clientAddressWidgetSignal(deleteIndex); 420 | } 421 | 422 | void Widget::sendStateDisplaySlot(QString msg, QString info) 423 | { 424 | if(msg == "服务器开始发送消息") 425 | { 426 | /*消息框*/ 427 | // QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳 428 | // qDebug()<<"addMessage" << info << time << ui->listWidget->count(); 429 | // dealMessageTime(time); 430 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), IPAddress); 431 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 432 | // dealMessage(messageW, item, info, time, QNChatMessage::User_Me); 433 | //// else { 434 | //// if(clientInfo != "") { 435 | //// dealMessageTime(time); 436 | 437 | //// QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget()); 438 | //// QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 439 | //// dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_Consumer); 440 | //// } 441 | //// } 442 | // ui->listWidget->setCurrentRow(ui->listWidget->count()-1); 443 | } 444 | else if(msg == "服务器发送消息成功") 445 | { 446 | qDebug() << "6666666"; 447 | /*暂停发送消息状态*/ 448 | qDebug() << ui->listWidget->count(); 449 | qDebug() << info; 450 | for(int i = ui->listWidget->count() - 1; i > 0; i--) { 451 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i)); 452 | if(messageW->text() == info) { 453 | qDebug() << "7777777"; 454 | messageW->setTextSuccess(); 455 | } 456 | } 457 | 458 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 459 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 460 | ui->textEdit->append(current_date + " —— " + msg); 461 | } 462 | else 463 | { 464 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 465 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 466 | ui->textEdit->append(current_date + " —— " + msg); 467 | } 468 | } 469 | 470 | void Widget::sendInfoDisplaySlot(QString clientInfo, QString ip) 471 | { 472 | 473 | /*消息框*/ 474 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳 475 | qDebug()<<"addMessage" << clientInfo << time << ui->listWidget->count(); 476 | if(clientInfo != "") { 477 | dealMessageTime(time); 478 | 479 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ip); 480 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget); 481 | dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_Consumer); 482 | } 483 | 484 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1); 485 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/ 486 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); 487 | ui->textEdit->append(current_date + " —— " + "服务器接收消息成功"); 488 | // QMessageBox::about(NULL, "客户端消息", clientInfo); 489 | } 490 | 491 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/ 492 | //void Widget::DfsFolder(std::string path,int layer) 493 | //{ 494 | // _finddata_t file_info; 495 | // std::string current_path=path+"/*.*"; //也可以用/*来匹配所有 496 | // int handle=_findfirst(current_path.c_str(),&file_info); 497 | // /*返回值为-1则查找失败*/ 498 | // if(-1==handle) 499 | // { 500 | // std::cout<<"cannot match the path"< 5 | #include "myserver.h" 6 | #include "debugonoroff.h" 7 | #include "qnchatmessage.h" 8 | class string; 9 | class QEvent; 10 | class Myserver; 11 | class QListWidgetItem; 12 | namespace Ui { 13 | class Widget; 14 | } 15 | 16 | 17 | class Widget : public QWidget 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit Widget(QWidget *parent = 0); 23 | ~Widget(); 24 | /*重新实现事件过滤器函数*/ 25 | // bool eventFilter(QObject *watched, QEvent *event); 26 | /*消息框*/ 27 | void dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type); 28 | void dealMessageTime(QString curMsgTime); 29 | /*获得发送文件列表*/ 30 | void getSendFileList(QString path); 31 | protected: 32 | void resizeEvent(QResizeEvent *event); 33 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/ 34 | // void DfsFolder(std::string path,int layer); 35 | /*层次遍历当前目录下的文件夹及子文件夹下的文件*/ 36 | // bool TraverseFiles(std::string path,int &file_num); 37 | signals: 38 | /*客户端主动断开连接信号*/ 39 | void closeClientConnectSignal(int disconnectCommand); 40 | /*客户端被动断开连接信号*/ 41 | void clientDiconnectSignal(int ID); 42 | /*获得文件列表信号*/ 43 | void getFileListSignal(QString filelist); 44 | /*发送文件信号*/ 45 | void sendFileWidgetSignal(QString filename); 46 | /*发送消息信号*/ 47 | void sendInfoWidgetSignal(QString info); 48 | /*服务器发送断开信号*/ 49 | void clientAddressWidgetSignal(int deleteIndex); 50 | public slots: 51 | /*添加客户端连接信息到界面中*/ 52 | // void addClientIPTGUISlot(QString CIP,int CPort,int ID,int state); 53 | /*客户端主动断开连接*/ 54 | void closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time); 55 | /*添加文件夹*/ 56 | void addFilePBSlot(); 57 | /*删除文件列表条目*/ 58 | void deleteFile(); 59 | /*显示日志信息*/ 60 | void displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time); 61 | // void deleteFileListItem(); 62 | // /*List Widget双击事件槽函数*/ 63 | // void doubleClickedItem(); 64 | /*删除消息内容*/ 65 | void deleteInfo(); 66 | /*传输文件按钮槽函数*/ 67 | void fileTranferButtonSlot(); 68 | /*消息传输按钮槽函数*/ 69 | void infoTranferButtonSlot(); 70 | /*发送状态在GUI中显示*/ 71 | void sendStateDisplaySlot(QString msg, QString info); 72 | /*发送消息在GUI中显示*/ 73 | void sendInfoDisplaySlot(QString clientInfo, QString ip); 74 | /*服务器主动断开槽函数*/ 75 | void clientAddressSlot(QString IP, int clientPort); 76 | private: 77 | Ui::Widget *ui; 78 | /*断开客户端连接命令,1表示断开*/ 79 | int closeCommand; 80 | /*存储添加的文件夹路径*/ 81 | QString dirPath; 82 | /*文件列表指针*/ 83 | FILE *fp; 84 | /*传输的消息内容*/ 85 | QString info; 86 | /*本机IP*/ 87 | QString ipAddress; 88 | QVector IPOrder; //记录listWidget_2里的客户端IP地址 89 | int index = 0; //记录listWidget_2当前索引 90 | /*断开连接 服务器 0 客户端 1*/ 91 | int closeFlag_previous = 1; 92 | int closeFlag_current = 1; 93 | Myserver *server; 94 | /*目录列表存储结构体*/ 95 | struct DirInformation{ 96 | char fileName[260]; //文件名字 97 | char dirName[260]; //目录名字 98 | unsigned int isDirectory; //是否是目录 99 | unsigned int isFile; //是否是文件 100 | unsigned int topDir; //是否是顶层目录 101 | }; 102 | struct DirInformation dirInfo; 103 | /*是目录*/ 104 | void ISDir() 105 | { 106 | dirInfo.topDir = 0; 107 | strcpy(dirInfo.fileName," "); 108 | dirInfo.isDirectory = 1; 109 | dirInfo.isFile = 0; 110 | } 111 | /*是文件*/ 112 | void ISFile() 113 | { 114 | dirInfo.topDir = 0; 115 | strcpy(dirInfo.dirName," "); 116 | dirInfo.isDirectory = 0; 117 | dirInfo.isFile = 1; 118 | } 119 | 120 | }; 121 | 122 | #endif // WIDGET_H 123 | -------------------------------------------------------------------------------- /Server/widget.h.autosave: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------- 2 | # 3 | # Project created by QtCreator 4 | # Author: 打代码的小陈 5 | # Info: Qt5局域网多线程数据传输(服务端)实现 6 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832 7 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt 8 | # 9 | #-------------------------------------------------*/ 10 | #ifndef WIDGET_H 11 | #define WIDGET_H 12 | 13 | #include 14 | #include "myserver.h" 15 | #include "debugonoroff.h" 16 | #include "qnchatmessage.h" 17 | class string; 18 | class QEvent; 19 | class Myserver; 20 | class QListWidgetItem; 21 | namespace Ui { 22 | class Widget; 23 | } 24 | 25 | 26 | class Widget : public QWidget 27 | { 28 | Q_OBJECT 29 | 30 | public: 31 | explicit Widget(QWidget *parent = 0); 32 | ~Widget(); 33 | /*重新实现事件过滤器函数*/ 34 | // bool eventFilter(QObject *watched, QEvent *event); 35 | /*消息框*/ 36 | void dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type); 37 | void dealMessageTime(QString curMsgTime); 38 | /*获得发送文件列表*/ 39 | void getSendFileList(QString path); 40 | protected: 41 | void resizeEvent(QResizeEvent *event); 42 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/ 43 | // void DfsFolder(std::string path,int layer); 44 | /*层次遍历当前目录下的文件夹及子文件夹下的文件*/ 45 | // bool TraverseFiles(std::string path,int &file_num); 46 | signals: 47 | /*客户端主动断开连接信号*/ 48 | void closeClientConnectSignal(int disconnectCommand); 49 | /*客户端被动断开连接信号*/ 50 | void clientDiconnectSignal(int ID); 51 | /*获得文件列表信号*/ 52 | void getFileListSignal(QString filelist); 53 | /*发送文件信号*/ 54 | void sendFileWidgetSignal(QString filename); 55 | /*发送消息信号*/ 56 | void sendInfoWidgetSignal(QString info); 57 | /*服务器发送断开信号*/ 58 | void clientAddressWidgetSignal(int deleteIndex); 59 | public slots: 60 | /*添加客户端连接信息到界面中*/ 61 | // void addClientIPTGUISlot(QString CIP,int CPort,int ID,int state); 62 | /*客户端主动断开连接*/ 63 | void closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time); 64 | /*添加文件夹*/ 65 | void addFilePBSlot(); 66 | /*删除文件列表条目*/ 67 | void deleteFile(); 68 | /*显示日志信息*/ 69 | void displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time); 70 | // void deleteFileListItem(); 71 | // /*List Widget双击事件槽函数*/ 72 | // void doubleClickedItem(); 73 | /*删除消息内容*/ 74 | void deleteInfo(); 75 | /*传输文件按钮槽函数*/ 76 | void fileTranferButtonSlot(); 77 | /*消息传输按钮槽函数*/ 78 | void infoTranferButtonSlot(); 79 | /*发送状态在GUI中显示*/ 80 | void sendStateDisplaySlot(QString msg, QString info); 81 | /*发送消息在GUI中显示*/ 82 | void sendInfoDisplaySlot(QString clientInfo, QString ip); 83 | /*服务器主动断开槽函数*/ 84 | void clientAddressSlot(QString IP, int clientPort); 85 | private: 86 | Ui::Widget *ui; 87 | /*断开客户端连接命令,1表示断开*/ 88 | int closeCommand; 89 | /*存储添加的文件夹路径*/ 90 | QString dirPath; 91 | /*文件列表指针*/ 92 | FILE *fp; 93 | /*传输的消息内容*/ 94 | QString info; 95 | /*本机IP*/ 96 | QString ipAddress; 97 | QVector IPOrder; //记录listWidget_2里的客户端IP地址 98 | int index = 0; //记录listWidget_2当前索引 99 | /*断开连接 服务器 0 客户端 1*/ 100 | int closeFlag_previous = 1; 101 | int closeFlag_current = 1; 102 | Myserver *server; 103 | /*目录列表存储结构体*/ 104 | struct DirInformation{ 105 | char fileName[260]; //文件名字 106 | char dirName[260]; //目录名字 107 | unsigned int isDirectory; //是否是目录 108 | unsigned int isFile; //是否是文件 109 | unsigned int topDir; //是否是顶层目录 110 | }; 111 | struct DirInformation dirInfo; 112 | /*是目录*/ 113 | void ISDir() 114 | { 115 | dirInfo.topDir = 0; 116 | strcpy(dirInfo.fileName," "); 117 | dirInfo.isDirectory = 1; 118 | dirInfo.isFile = 0; 119 | } 120 | /*是文件*/ 121 | void ISFile() 122 | { 123 | dirInfo.topDir = 0; 124 | strcpy(dirInfo.dirName," "); 125 | dirInfo.isDirectory = 0; 126 | dirInfo.isFile = 1; 127 | } 128 | 129 | }; 130 | 131 | #endif // WIDGET_H 132 | -------------------------------------------------------------------------------- /Server/widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Widget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 832 10 | 699 11 | 12 | 13 | 14 | Widget 15 | 16 | 17 | 18 | 19 | 14 20 | 11 21 | 808 22 | 677 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 35 | 36 | 37 | 客户端状态: 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 0 50 | 51 | 52 | 53 | 文件信息: 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 选择文件 68 | 69 | 70 | 71 | 72 | 73 | 74 | 删除文件 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 传输文件 86 | 87 | 88 | 89 | 90 | 91 | 92 | 消息信息: 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 16777215 101 | 100 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 传输消息 112 | 113 | 114 | 115 | 116 | 117 | 118 | 清空消息 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 运行日志: 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 消息对话: 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 330 150 | 0 151 | 152 | 153 | 154 | 155 | 330 156 | 16777215 157 | 158 | 159 | 160 | QListWidget{background-color: rgb(247, 247, 247); color:rgb(51,51,51); border: 1px solid rgb(247, 247, 247);outline:0px;} 161 | QListWidget::Item{background-color: rgb(247, 247, 247);} 162 | QListWidget::Item:hover{background-color: rgb(247, 247, 247); } 163 | QListWidget::item:selected{ 164 | background-color: rgb(247, 247, 247); 165 | color:black; 166 | border: 1px solid rgb(247, 247, 247); 167 | } 168 | QListWidget::item:selected:!active{border: 1px solid rgb(247, 247, 247); background-color: rgb(247, 247, 247); color:rgb(51,51,51); } 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | --------------------------------------------------------------------------------