飛鴿傳書源碼分析四-訊息發送,飛鴿傳書源碼

來源:互聯網
上載者:User

飛鴿傳書源碼分析四-訊息發送,飛鴿傳書源碼

轉載請註明出處:http://blog.csdn.net/mxway/article/details/44569831
本篇文章是在飛鴿傳書源碼v2.06的基礎上進行分析的
飛鴿傳書是一款工作在區域網路的軟體,支援區域網路裡不同裝置之間的訊息發送及檔案的傳輸(訊息發送使用udp,檔案傳輸使用tcp)。
發送訊息及檔案傳輸是在飛鴿傳書的發送對話方塊中進行,而發送對話方塊的開啟是通過雙擊拖盤(win7系統)到工作列的表徵圖。而拖盤到工作列的這個表徵圖就是飛鴿傳書的主視窗,對應的源碼就是Mainwin.cpp中的TMainWin類。下面是TMainWin類處理雙擊事件,滑鼠雙擊事件為什麼是由EventButton進行處理可以參見第二篇文章-訊息機制

BOOL TMainWin::EventButton(UINT uMsg, int nHitTest, POINTS pos){    switch (uMsg)    {         ...    case WM_LBUTTONDBLCLK:    case WM_NCLBUTTONDBLCLK:        if (cfg->OneClickPopup == FALSE)            SendDlgOpen();        return  TRUE;         ...    }}BOOL TMainWin::SendDlgOpen(HWND hRecvWnd, MsgBuf *msg){    TSendDlg *sendDlg;    ...    if ((sendDlg = new TSendDlg(msgMng, shareMng, &hosts, cfg, logmng, hRecvWnd, msg)) == NULL)        return  FALSE;    sendList.AddObj(sendDlg);    sendDlg->Create(), sendDlg->Show();    ...}BOOL TDlg::Create(HINSTANCE hInstance){    TApp::AddWin(this);    if ((hWnd = ::CreateDialog(hInstance ? hInstance : TApp::hI, resId ? (LPCSTR)resId : resName, parent ? parent->hWnd : NULL, (DLGPROC)TApp::WinProc)) == NULL)        return  TApp::DelWin(this), FALSE;    else        return  TRUE;}

發送訊息的對話方塊類似如下

在發送對話方塊中在編輯框中輸入要發送的內容,在使用者列表中選擇要發送的對象,點send按鈕就可以將訊息發送到對方。這裡可以選擇對發送的訊息是否進行加密,為了簡化問題這裡只分析最簡單的訊息發送。

一、飛鴿傳書訊息發送格式
飛鴿傳書版本:資料包唯一編號:使用者名稱:機器名稱:命令:真實訊息
(1)飛鴿傳書版本是一個宏定義

#define IPMSG_VERSION           0x0001

(2)資料包唯一編號由飛鴿傳書程式自動產生的。
(3)使用者名稱:如果使用者沒有使用飛鴿傳書設定自己的名稱,預設使用的是當前登入系統的使用者名稱
(4)機器名稱,裝置的名稱如PC設定的電腦名稱
(5)命令,命令是一個32位的無符號數,其功能分為兩部分,後8位用於必選的命令,表示當對方收到該命令後要什麼事,如使用者上線通知,使用者退出通知,發送訊息。前面24位用於可選命令,如對傳送訊息進行加密,擷取加密的密鑰等。
(6)真實訊息,這個是真正要發給對方的資訊,包括要發送對方的訊息及要傳送給對方的檔案資訊。
產生上述格式訊息的代碼如下

ULONG MsgMng::MakeMsg(char *buf, int _packetNo, ULONG command, const char *msg, const char *exMsg, int *packet_len){    int     len, ex_len = exMsg ? strlen(exMsg) + 1 : 0, max_len = MAX_UDPBUF;    if (packet_len == NULL)        packet_len = &len;        //版本:資料包編號:使用者名稱:裝置名稱:命令:    *packet_len = wsprintf(buf, "%d:%ld:%s:%s:%ld:", IPMSG_VERSION, _packetNo, local.userName, local.hostName, command);    if (ex_len + *packet_len + 1 >= MAX_UDPBUF)        ex_len = 0;    max_len -= ex_len;    if (msg != NULL)    //LocalNewLineToUnix把\r\n轉換為\n        *packet_len += LocalNewLineToUnix(msg, buf + *packet_len, max_len - *packet_len);    (*packet_len)++;    if (ex_len)    {        //如果有附加訊息(如檔案發送,同時發送附加的訊息)        memcpy(buf + *packet_len, exMsg, ex_len);        *packet_len += ex_len;    }    return  _packetNo;}

二、訊息發送
單擊send按鈕的實現代碼如下:

BOOL TSendDlg::EvCommand(WORD wNotifyCode, WORD wID, LPARAM hWndCtl){    switch (wID)    {    case IDOK:        ...        SendMsg();        ...    }}BOOL TSendDlg::SendMsg(void){    command = IPMSG_SENDMSG|IPMSG_SENDCHECKOPT;    //擷取選中數    if ((sendEntryNum = (int)SendDlgItemMessage(HOST_LIST, LVM_GETSELECTEDCOUNT, 0, 0)) <= 0 || (sendEntry = new SendEntry [sendEntryNum]) == NULL)        return  FALSE;    //擷取要發送的訊息資料    GetDlgItemText(SEND_EDIT, msg.msgBuf, MAX_UDPBUF);    int storeCnt = 0, status = 0, cnt;    int localStatus = sendEntryNum <= cfg->EncryptNum && (cfg->pubKey.Key() || cfg->smallPubKey.Key()) ? IPMSG_ENCRYPTOPT : 0;    //擷取選中的host資訊,host資訊是由TMainWin傳過來的    for (cnt=0; cnt < memberCnt && storeCnt < sendEntryNum; cnt++)    {        if ((SendDlgItemMessage(HOST_LIST, LVM_GETITEMSTATE, cnt, LVIS_SELECTED) & LVIS_SELECTED) == 0)            continue;        char        hostStr[MAX_LISTBUF];        Host        *host = hostArray[cnt];        SendEntry   *entry = &sendEntry[storeCnt++];        //發送的訊息要進行加密        status |= host->hostStatus & IPMSG_ENCRYPTOPT;        MakeListString(cfg, host, hostStr);        logmng->WriteSendHead(hostStr);        entry->SetHost(host);        entry->SetStatus((localStatus & host->hostStatus) ? host->pubKey.Key() == NULL ? ST_GETCRYPT : ST_MAKECRYPTMSG : ST_MAKEMSG);        entry->SetCommand(command | (entry->Status() == ST_MAKEMSG ? 0 : IPMSG_ENCRYPTOPT));    }    //發送的訊息太長進行截斷    msg.msgBuf[MAX_CRYPTLEN] = 0;       if (status &= localStatus)          command |= IPMSG_ENCRYPTOPT;    logmng->WriteSendMsg(msg.msgBuf, command, shareInfo);    if (shareInfo && shareInfo->fileCnt)        // ...\0no:fname:size:mtime:    {        //如果選中的檔案或檔案夾進行傳輸,產生要傳輸的檔案資訊        char    buf[MAX_UDPBUF / 2];        EncodeShareMsg(shareInfo, buf, sizeof(buf));        shareStr = new char [strlen(buf) + 1];        strcpy(shareStr, buf);        shareMng->AddHostShare(shareInfo, sendEntry, sendEntryNum);    }    //真正進行發送訊息的函數    SendMsgSub();    return  TRUE;}BOOL TSendDlg::SendMsgSub(void){    BOOL    makeNomalMsg = TRUE;        for (int cnt=0; cnt < sendEntryNum; cnt++)    {        //如果需要從要發送的客戶那擷取加密的密鑰,先擷取密鑰        if (sendEntry[cnt].Status() == ST_GETCRYPT) {            char    spec_str[MAX_BUF];            int     spec = IPMSG_RSA_512 | IPMSG_RC2_40;            if (cfg->pubKey.Key())                spec |= IPMSG_RSA_1024 | IPMSG_BLOWFISH_128;            wsprintf(spec_str, "%x", spec);            msgMng->Send(&sendEntry[cnt].Host()->hostSub, IPMSG_GETPUBKEY, spec_str);        }        //對要發送的資料進行加密        if (sendEntry[cnt].Status() == ST_MAKECRYPTMSG) {            MakeEncryptPacket(sendEntry + cnt);     // ST_MAKECRYPTMSG -> ST_SENDMSG        }        if (sendEntry[cnt].Status() == ST_MAKEMSG) {            sendEntry[cnt].SetStatus(ST_SENDMSG);            if (makeNomalMsg)                msgMng->MakeMsg(msgBuf, packetNo, command & ~IPMSG_ENCRYPTOPT, msg.msgBuf, shareStr, &packetLen), makeNomalMsg = FALSE;        }        //在MakeEncryptPacket對訊息加密完成後設定host狀態為ST_SENDMSG        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);        }    }    return  TRUE;}

下面是使用wireshark抓取的使用飛鴿傳書發送訊息的一個資料包。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.