1. 程式人生 > >飛鴿傳書原始碼分析五-檔案傳輸

飛鴿傳書原始碼分析五-檔案傳輸

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可以認