首页 / 更多教程 / 飞鸽传书源码分析四-消息发送
飞鸽传书源码分析四-消息发送
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了飞鸽传书源码分析四-消息发送,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5566字,纯文字阅读大概需要8分钟。
内容图文
转载请注明出处: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();
returnTRUE;
...
}
}
BOOL TMainWin::SendDlgOpen(HWND hRecvWnd, MsgBuf *msg)
{
TSendDlg *sendDlg;
...if ((sendDlg = new TSendDlg(msgMng, shareMng, &hosts, cfg, logmng, hRecvWnd, msg)) == NULL)
returnFALSE;
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;
elsereturnTRUE;
}
发送消息的对话框类似如下
在发送对话框中在编辑框中输入要发送的内容,在用户列表中选择要发送的对象,点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)
returnFALSE;
//获取要发送的消息数据
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();
returnTRUE;
}
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_SENDMSGif (sendEntry[cnt].Status() == ST_SENDMSG) {
constchar *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);
}
}
returnTRUE;
}
下面是使用wireshark抓取的使用飞鸽传书发送消息的一个数据包。
原文:http://blog.csdn.net/mxway/article/details/44569831
内容总结
以上是互联网集市为您收集整理的飞鸽传书源码分析四-消息发送全部内容,希望文章能够帮你解决飞鸽传书源码分析四-消息发送所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。