飛鴿傳書原始碼分析五-檔案傳輸
1.新增要傳送的檔案
檔案的傳送是在傳送對話方塊中進行的,首先找到傳送對話方塊的快捷選單。
File Transfer對應的選單id為MENU_FILEADD,相應的command處理事件在Senddlg.cpp中的EvCommand函式中
BOOL TSendDlg::EvCommand(WORD wNotifyCode, WORD wID, LPARAM hWndCtl)
{
switch (wID)
{
case MENU_FILEADD:
{
char buf[MAX_PATH] = "";
if (TShareDlg::FileAddDlg(this, shareMng, shareInfo ? shareInfo : (shareInfo = shareMng->CreateShare(packetNo)), cfg))
{
SetFileButton(this, FILE_BUTTON, shareInfo);
EvSize(SIZE_RESTORED, 0, 0);
}
}
break;
}
}
BOOL TShareDlg::FileAddDlg(TDlg *dlg, ShareMng *shareMng, ShareInfo *shareInfo, Cfg *cfg)
{
char buf[MAX_BUF] = "", path[MAX_BUF];
//開啟檔案對話方塊,OpenFileDlg::MULTI_OPEN設定可以同時開啟多個檔案
if (OpenFileDlg(dlg, OpenFileDlg::MULTI_OPEN).Exec(buf, ADDFILE_MSGSTR, OPENFILEALL_MSGSTR, cfg->lastOpenDir) != TRUE)
return FALSE;
//獲取開啟檔案的路徑字元長度
int dirlen = strlen(cfg->lastOpenDir);
//如果只選擇一個檔案,直接將檔案加入到待發送檔案的快取區shareInfo中
if (buf[dirlen])
return shareMng->AddFileShare(shareInfo, buf);
//如果選擇了多個檔案,迴圈將每個檔案都加入到待發送檔案快取區中
for (char *fname=buf+dirlen+1; *fname; fname += strlen(fname) +1)
{
if (MakePath(path, buf, fname) >= MAX_PATH)
continue;
shareMng->AddFileShare(shareInfo, path);
}
return TRUE;
}
開啟檔案對話方塊的呼叫是在OpenFileDlg類中的Exec中呼叫Win32的API GetOpenFileName()函式實現的。
2. 待發送檔案的儲存結構
從TShareDlg::FileAddDlg函式中可以看到待發送的檔案是儲存到Sh
areInfo類中。ShareInfo的宣告如下
struct ShareInfo : public TListObj {
int packetNo; //
Host **host; // 要傳送的目的機器列表
int hostCnt; // 要傳送的目的機器個數
char *transStat; //
FileInfo **fileInfo; // 要傳輸的檔案資訊
int fileCnt; // 要傳輸的檔案個數
FILETIME attachTime;
...
};
class FileInfo : public TListObj {
int id; // 要傳輸檔案的id
char *fname; //檔名
const char *fname_ext; // for recv dir thread
UINT attr; //檔案的屬性,如是檔案或資料夾,只讀等
_int64 size; //檔案大小
time_t mtime; //檔案最後一次修改時間
time_t atime; //檔案最後一次訪問時間
time_t crtime; //檔案建立時間
BOOL isSelected; // for recvdlg
...
}
再回到TShareDlg::FileAddDlg中,看shareMng->AddFileShare(shareInfo, path);
BOOL ShareMng::AddFileShare(ShareInfo *info, char *fname)
{
//如果要傳送的檔案已經加入到列表中,不再進行處理
for (int cnt=0; cnt < info->fileCnt; cnt++)
if (strcmp(fname, info->fileInfo[cnt]->Fname()) == 0)
return FALSE;
FileInfo *fileInfo = new FileInfo;
//設定新的待發送檔案資訊,如檔案大小,最後一次修改時間等
if (SetFileInfo(fname, fileInfo) == FALSE)
return FALSE;
//如果fileInfo分配的記憶體已經使用完,需要分配理多的記憶體,用於存放新的檔案資訊
if ((info->fileCnt % BIG_ALLOC) == 0)
info->fileInfo = (FileInfo **)realloc(info->fileInfo, (info->fileCnt + BIG_ALLOC) * sizeof(FileInfo *));
info->fileInfo[info->fileCnt] = fileInfo;
info->fileCnt++;
return TRUE;
}
3. 在網路中進行檔案傳輸
(1)檔案在網路上進行傳時的格式。
id:檔名:檔案大小:最後一次修改時間:檔案屬性:
如果多個檔案則多個檔案之間的資訊加入一個’\a’字元進行分隔。
(2)在Senddlg.cpp中的SendMsg,即按”Send”按鈕的觸發事件,其程式碼如下
BOOL TSendDlg::SendMsg(void)
{
...
if (shareInfo && shareInfo->fileCnt)
command |= IPMSG_FILEATTACHOPT;
...
if (shareInfo && shareInfo->fileCnt)
{
char buf[MAX_UDPBUF / 2];
//將檔案生成(1)中的格式
EncodeShareMsg(shareInfo, buf, sizeof(buf));
shareStr = new char [strlen(buf) + 1];
strcpy(shareStr, buf);
shareMng->AddHostShare(shareInfo, sendEntry, sendEntryNum);
}
SendMsgSub();
...
}
BOOL EncodeShareMsg(ShareInfo *info, char *buf, int bufsize)
{
int offset=0;
char fname[MAX_PATH];
*buf = 0;
for (int cnt=0; cnt < info->fileCnt; cnt++)
{
ForcePathToFname(info->fileInfo[cnt]->Fname(), fname);
info->fileInfo[cnt]->SetId(cnt);
offset += wsprintf(buf + offset, (info->fileInfo[cnt]->Size() >> 32) ? "%d:%s:%x%08x:%x:%s" : "%d:%s:%x%x:%x:", cnt, fname, (int)(info->fileInfo[cnt]->Size() >> 32), (int)info->fileInfo[cnt]->Size(), info->fileInfo[cnt]->Mtime());
offset += wsprintf(buf + offset, "%x:", info->fileInfo[cnt]->Attr());
offset += wsprintf(buf + offset, "%c", FILELIST_SEPARATOR);
if (offset + MAX_BUF > bufsize)
break;
}
return TRUE;
}
SendMsgSub()中會對待發送的訊息進行加密(傳輸的檔案資訊不進行加密)。
BOOL TSendDlg::SendMsgSub(void)
{
for (int cnt=0; cnt < sendEntryNum; cnt++)
{
if (sendEntry[cnt].Status() == ST_MAKECRYPTMSG) {
MakeEncryptPacket(sendEntry + cnt);
}
...
if (sendEntry[cnt].Status() == ST_SENDMSG) {
const char *str = sendEntry[cnt].Msg() ? sendEntry[cnt].Msg() : msgBuf;
int len = sendEntry[cnt].Msg() ? sendEntry[cnt].MsgLen() : packetLen;
msgMng->UdpSend(sendEntry[cnt].Host()->hostSub.addr, sendEntry[cnt].Host()->hostSub.portNo, str, len);
}
...
}
}
下面是使用飛鴿傳軟體傳送檔案的一個截圖
圖中紅色框中就是要傳送的檔案資訊,從圖中可以看出傳送的檔名為open_data_structures.pdf,檔案大小是十六進位制的01817d0位元組,最後一次修改時間為十六進位制53f492fe。
4.接收端的處理
現在只是將待發送的檔案資訊傳送出去,但是還沒有將真正的檔案內容傳出去。檔案內容的傳輸是通過TCP進行的。
Mainwin接收到傳送來的udp訊息後會對udp的訊息進行處理。udp的處理在Mainwin.cpp的UdpEvent函式中。
BOOL TMainWin::UdpEvent(LPARAM lParam)
{
MsgBuf msg;
if (WSAGETSELECTERROR(lParam) || msgMng->Recv(&msg) != TRUE)
return FALSE;
...
switch (GET_MODE(msg.command))
{
...
case IPMSG_SENDMSG:
//處理髮送來的訊息
MsgSendMsg(&msg);
break;
...
}
...
}
void TMainWin::MsgSendMsg(MsgBuf *msg)
{
...
RecvDlgOpen(msg);
...
}
BOOL TMainWin::RecvDlgOpen(MsgBuf *msg)
{
TRecvDlg *recvDlg;
...
if ((recvDlg = new TRecvDlg(msgMng, msg, &hosts, cfg, logmng)) == NULL)
return FALSE;
...
recvDlg->Create();
recvDlg->Show();
recvDlg->SetForceForegroundWindow();
...
}
當接收端收到了訊息後就會開啟接收對話方塊。下面看下接收對話方塊的建構函式及接收對話方塊的EvCreate對話方塊
TRecvDlg::TRecvDlg(MsgMng *_msgMng, MsgBuf *_msg, THosts *_hosts, Cfg *_cfg, LogMng *_logmng) : TListDlg(RECEIVE_DIALOG), editSub(_cfg, this)
{
...
//可選欄位中有傳輸檔案的選項命令
if (msg.command & IPMSG_FILEATTACHOPT)
{
//從接收到的訊息中解析出檔案的資訊
if ((shareInfo = DecodeShareMsg(msg.msgBuf + msg.exOffset)) != NULL)
{
fileObj = new RecvFileObj;
memset(fileObj, 0, sizeof(RecvFileObj));
}
}
...
}
BOOL TRecvDlg::EvCreate(LPARAM lParam)
{
...
if (msg.command & IPMSG_SECRETOPT)
::ShowWindow(GetDlgItem(RECV_EDIT), SW_HIDE), ::ShowWindow(GetDlgItem(QUOTE_CHECK), SW_HIDE);
else {
::ShowWindow(GetDlgItem(OPEN_BUTTON), SW_HIDE), openFlg = TRUE;
//將檔名顯示到按鈕中
if (shareInfo)
SetFileButton(this, FILE_BUTTON, shareInfo);
}
...
}
RecvDlg如下
在出現的對話方塊中,點選”open_data_structures.pdf”這個按鈕。會彈出一個儲存檔案的對話方塊。點儲存後文件的傳輸就會開始。關於檔案的具體傳輸程式碼分析,下一篇再詳細解析。
相關推薦
飛鴿傳書原始碼分析五-檔案傳輸
1.新增要傳送的檔案 檔案的傳送是在傳送對話方塊中進行的,首先找到傳送對話方塊的快捷選單。 File Transfer對應的選單id為MENU_FILEADD,相應的command處理事件在Senddlg.cpp中的EvCommand函式中 B
【181029】FreeEIM 飛鴿傳書仿QQ即時通訊軟體VC++原始碼
FreeEIM 仿QQ功能的企業即時通訊軟體VC++的原始碼,最後更新於2010年8月份,完成資料庫更改的任務。將聊天記錄改用資料庫形式,暫且使用Access。 本軟體的視窗和功能都與QQ有點相似,可傳送檔案、視窗抖動、傳送表情等修改功能,並儘量去除所有不相關內容,堅決不對使用者敏感內容作任
飛鴿傳書官方網站 2012 最新原始碼公開
善於學習,對於任何職業而言,都是前進所必需的 飛鴿傳書官方網站,對於飛秋區域網聊天,這種要求就更加高了。但是學習也要找對目標,一些小coding fans們,他們也津津樂道於他們的學習能力,一會學會了asp,一會兒學會了php,一會兒學會了jsp,他們把這個作為炫耀的資本,盲目
IPMSG飛鴿傳書1——編譯原始碼的方法
IP Messenger是一款區域網內部聊天、檔案傳輸工具,具有很多優點,如資料通訊不需要建立伺服器、直接在兩臺電腦間通訊和資料傳輸,支援檔案及檔案目錄的傳輸,安全快捷以及小巧方便等優異特點,因此很多公司都採用它作為部門、公司內部的IM即時通訊工具。 IP Messenger在程式結構方面採用了Win
飛鴿傳書2009綠色版 官方網站下載地址
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
驚現飛鴿傳書2009
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
飛鴿傳書是怎麼就變成飛秋了的
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
飛鴿傳書2011下載 飛鴿傳書
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
雲通信的變遷史:從飛鴿傳書到即時可達
雲通信行業開始迎來繁榮大發展,似乎已然成為了所有人的共識。在“信息就是生命”的時代,與信息相關的任何話題,都能輕松成為關註的焦點。 當互聯網的發展讓來自企業側的溝通需求急劇上升、越來越多企業開始關註雲通信,當用戶的生活日漸被互聯網信息切割,越來越多的用戶開始好奇雲通信……雲通信仿佛一只看不見
ubuntu 14.04 飛鴿傳書(QIpmsg) 2425 端口占用
最近新安裝了臺 ubuntu 14.04 系統的虛擬機器 。 為了便於和其他主機聯絡 安裝了個 飛鴿傳書 (QIpmsg ver.1.2.141211) 但是在使用的時候出現2425 端口占用。 問題重現: 正常安裝也能正常使用。 但是在最小化的時候 相當能的按照windo
飛鴿傳書:如何控制自己浮躁心理
心情浮躁的時候如何使自己平靜下來,平時可以做些什麼可以使自己儘量減少浮躁!那麼怎樣才能克服浮躁心理呢?飛鴿傳書今天總結了一下幾個方法,這裡和大家分享一下。 方法一:把自己房間的床單和枕巾顏色變成藍色,躺在床上,想象自己躺在一片大海之上,沒人打擾,拿幾個 水果放在房間,水果的
Linux下安裝飛鴿傳書
轉自 http://hi.baidu.com/dxjinf/blog/item/79be36515504e32042a75b97.html 在Linux下使用ipmsg(飛鴿傳書) ipmsg是個不錯的區域網通訊軟體,非常小巧,無需伺服器端,使用非常方便。 在Linux下使用
飛鴿傳書 繫結指定網絡卡
如果有多個網絡卡(IP), 你可以將飛鴿傳書與指定的網絡卡(IP)進行繫結. 命令格式如下(你可以在快捷方式上設定): ipmsg.exe [埠] /NIC IP地址 D:\Users\administrator\Desktop\ipmsg.exe
解決“飛鴿傳書”無法顯示區域網使用者的方法
最近飛鴿傳書 突然不能用了,顯示列表中就自己一個人,翻了N個網頁還是無法解決。一次偶然的操作,發現了其中的原因——飛鴿匹配的網絡卡不對! 右鍵飛鴿傳書——》 列表顯示設定——》
Java Socket:飛鴿傳書的網路套接字
在古代,由於通訊不便利,一些聰明的人就利用鴿子會飛且飛得比較快、會辨認方向的優點,對其進行了馴化,用來進行訊息的傳遞——也就是所謂的“飛鴿傳書”。而在 Java 中,網路套接字(Socket)扮演了同樣的角色。 套接字(Socket)是一個抽象層,應用程
JDK原始碼分析(五)——HashSet
目錄 HashSet概述 內部欄位及構造方法 儲存元素 刪除元素 包含元素 總結 HashSet概述 從前面開始,已經分析過集合中的List和Map,今天來介紹另一種集合元素:Set。這是JDK對HashSet的介紹: This class implements
NSQ原始碼分析(五)——Channel
Channel相關的程式碼主要位於nsqd/channel.go, nsqd/nsqd.go中。 Channel是消費者訂閱特定Topic的一種抽象。對於發往Topic的訊息,nsqd向該Topic下的所有Channel投遞訊息,而同一個Channel只投遞一次,Channel下如果
從SpringBoot原始碼分析 配置檔案的載入原理和優先順序
從SpringBoot原始碼分析 配置檔案的載入原理和優先順序 本文從SpringBoot原始碼分析 配置檔案的載入原理和配置檔案的優先順序 跟入原始碼之前,先提一個問題: SpringBoot 既可以載入指定目錄下的配置檔案獲取配置項,也可
Tomcat的原始碼分析(五)-Pipeline-value管道
一、Tomcat的Pipeline-value管道實現 Pipeline管道的實現分為生命週期管理和處理請求。 在Engin的管道中依次執行Engin的各個Value,最後執行StandardEnginValue,依次類推StandardWrapperVa
RabbitMQ客戶端原始碼分析(五)之ConsumerWorkSerivce與WorkPool
RabbitMQ-java-client版本 com.rabbitmq:amqp-client:4.3.0 RabbitMQ版本宣告: 3.6.15 WorkPool WorkPool可以認