因为油槽是基于广播的,服务器端做为接受点,客户端做为发送端;
使用油槽实现进程间的通信。
1. 服务器端创建油槽 重点字串说明 服务器和客户端
HANDLE hMailslot=CreateMailslot(".//mailslot//mailslot",0,MAILSLOT_WAIT_FOREVER,NULL);
if(INVALID_HANDLE_VALUE==hMailslot)
{
MessageBox("创建油槽失败!");
return;
}
相当于是建立了一个新的文件,文件的地址是//./mailslot/mailslot :
A:解释"/"是提示转义字符,后面一个/是需要的/反斜杠;
所以字符串中“//”表示的是一个/;
B:第一个mailslot表明是建立的一个油槽; 第二个是油槽的名字,可以自己选定;
C:// ./Mailslot/name 标定同一台机器上的一个本地邮槽
//servername/Mailslot/name 标定名为servername的一个远程邮槽服务器
// domainname/Mailslot/name 标定在指定的domain(域)内,使用特定name(名字)的所有邮槽
//*/Mailslot/name 标定系统主域内,标定特定name(名字)的所有邮槽
实验证明 实验证明 : 同一个机器上.//很好通信;
当访问远程,同一个局域网的计算机比如: 客户端:打开CreateFile(que//mailsot//mailsot",...:);
服务器:创建CReateMailslot(".//mailslot//mailslot");
实验证明 主题的思想就是 服务器端 创建油槽;并且只有服务器端能够从这个油槽文件读出数据;
客户端 打开【创建好】的油槽文件,并且向里面写入数据。 从而油槽文件可以在服务器上被读出来;
一句话,服务器创建文件,客户机打开并写入,服务器一直等着,然后读取出数据;
而所谓的一对多的通信,重点就在C:.//mailslot//mailslot 中第一个参数的指定打开File的范围上;本文档的写入,都是用事实和实验来说明的;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MFC实例 一对多的油槽通信
服务器端: 在一个Dialog的类中,一个BUNTTON 按钮,一个编辑框用于显示广播,添加BUTTON的Class组建,建立On_btnclicked
创建一个油槽;并且在一个死循环里,读出数据,并且把数据封装成WM_RECVDATA消息 ; 添加消息响应函数OnRecvData(WPARAM ,LPARAM), 在消息响应里面,把收到的数据显示在编辑框里;
客户端: 也是在一个Dialog类,先打开服务器创建的油槽文件,然后向里面写入数据。从一个编辑框里面读入数据,然后用写文件的函数,写入;可以把历史的消息都显示到一个编辑框里。
这个就是整个程序的思路.
下面可以贴一下重点代码:
void CMSDlg::OnBtnRecv() 实验证明 重点1 //客户端 创建油槽。que是同一个局域网的主机名 网络上的待研究
{
HANDLE hMailslot=CreateFile("que//mailslot//mailslot",GENERIC_WRITE,
FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hMailslot)
{
MessageBox("打開油槽失敗!");
return;
}
CString strTime; //时间的处理;
CTime time = CTime::GetCurrentTime(); //得到一个当前时间;
strTime=time.Format("%H:%M:%S"); //格式化为 20:30:10 小时:分钟:秒
/* CString strSend;
CString strTemp;
GetDlgItemText(IDC_EDIT_SEND,strSend); //从IDC_EDIT_SEND取出发送的数据;
GetDlgItemText(IDC_EDIT_HIS,strTemp);
strTemp+="/r/n";
strTemp+=strTime; //将当前时间和发送的数据都显示到IDC_EDIT_HIS
strTemp+="/r/n";
strTemp+="cc:";
strTemp+=strSend;*/
SetDlgItemText(IDC_EDIT_SEND,""); //清空发送数据的编辑框
SetDlgItemText(IDC_EDIT_HIS,strTemp); //将历史消息都显示到IDC_EDIT_HIS编辑框
strSend+="cc 廣播:";
DWORD dwWrite;
if(!WriteFile(hMailslot,strSend,strSend.GetLength()+1,&dwWrite,NULL))
{
MessageBox("写入失败!");
CloseHandle(hMailslot);
return; 实验证明 重点2://写入数据到服务器的油槽。
}
CloseHandle(hMailslot);
}
==================================================================================
服务器端 要先创建好油槽 才打开客户端
void CMSDlg::OnBtnRecv()
{
// TODO: Add your control notification handler code here
实验证明 重点1: //创建油槽,注意此处为.表示是本地主机
HANDLE hMailslot=CreateMailslot(".//mailslot//mailslot",0,
MAILSLOT_WAIT_FOREVER,NULL);
if(INVALID_HANDLE_VALUE==hMailslot)
{
MessageBox("创建油槽失败!");
return;
}
char buf[100];
DWORD dwRead;
int retval;
while(TRUE) 实 重点2 //在一个死循环中,不断的读取数据到buf,并且封装成WM_RECVDATA,消息,而buf里的数据,被传到消息的
{ //LPARAM中。 可以在消息响应函数中通过形式参数,读到buf数据;
retval=ReadFile(hMailslot,buf,100,&dwRead,NULL);
if(!retval)
{
CloseHandle(hMailslot);
MessageBox("读取数据失败!");
break;
}
实验证明 重点3 //形成用户自定义消息,设置消息参数;
if(::PostMessage(m_hWnd,WM_RECVDATA,0,(LPARAM)buf))
{
MessageBox("new message!");
}
}
CloseHandle(hMailslot);
}
顺便复习一下 利用自定义的消息 设定自定义的消息响应函数
A 在Dialog类的头文件上,#define WM_RECVDATA WM_USER+1 主要是使这个新的消息不会和别的消息重复了;
在Dialog类的cpp文件中,在消息映射的宏定义里面
BEGIN_MESSAGE_MAP(CMSDlg, CDialog)
//{{AFX_MSG_MAP(CMSDlg)
ON_WM_SYSCOMMAND()
。。。。(省略一些通过类Classward添加的函数)
//}}AFX_MSG_MAP
B ON_MESSAGE(WM_RECVDATA,OnRecvData) / /这里添加自己的消息响应函数;
END_MESSAGE_MAP()
在头文件中声明消息响应函数
//{{AFX_MSG(CMSDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnBtnRecv();
afx_msg void OnBtnClose();
//}}AFX_MSG
C afx_msg void OnRecvData(WPARAM wparam,LPARAM lparam); 在头文件中声明消息响应函数
DECLARE_MESSAGE_MAP()
到此 就完了 最后还做了下 Timer()
自己简单的理解,就是SetTimer(1,2000,NULL),这个函数的作用,每隔一秒钟就是发射WM_timer 消息;
然后,自己在ClassWard中,添加一个响应函数,ONTimer();
因为每秒钟都会有函数响应,所以在做时间的时候,就可以每隔一秒,都会读出当前时间,看起来,就是秒数在动;
所以实现这个时间动态显示的功能 先设定一个定时发射器,然后用on_timer()去读取当前时间,并且显示在对话框上;
而SetTimer(1,2000,NULL) 1:是自己的发射器的编号,2000 是发射器的时间限制在2000ms;NULL是响应函数的地址,为空就是默认的On_timer(); 而这个函数,放在对话框类的OnInitdialog()消息函数里面,就是窗口初始化的时候,就设定时间开始;
然后
void CMSCDlg::OnTimer(UINT nIDEvent) //在这里可以拿到你SetTimer(1,。。,。。)第一个参数的ID;
{ //可以判断下是不是你设定的那个定时器;
// TODO: Add your message handler code here and/or call default
time = CTime::GetCurrentTime();
SetDlgItemText(IDC_TIME,time.Format("%A, %B %d,%Y %H:%M:%S"));
CDialog::OnTimer(nIDEvent);
}
服务器端 客户端 多个服务器 使用*//mailslot//mailslot 实验就是能够广播
不过程序运行也是有一些问题。 在if(PostMessage())必须{实现MessageBox(“xxx”)函数} 不然死活都不会去调用相对应的消息响应函数 OnRecvData() ; 想要写一个线程函数,来发送读取的数据为消息; 也许能够解决这个问题,但是目前,觉得写到这里也行了,待进一步做~~