异步与同步通信相比较,前者是非阻塞模式,后者是阻塞模式。有关两者差异在此博主中有详细讲解,推荐:https://www.cnblogs.com/wzsblogs/p/4671559.html。

采用同步socket,同时可与CArchive、CSocketFile 配合使用(这两者能否与异步socket配合使用呢?还待验证)。两者的运行机制基本相同,但是在同步机制中OnConnect与OnSend永远不会被系统调用。(为啥?CSocket在Connect()返回WSAEWOULDBLOCK错误时,不是在OnConnect(),OnReceive()这些事件终端函数里去等待。它马上调用一个用于提取消息的函数PumpMessage(...),就是从当前线程的消息队列里取关心的消息。原文:https://www.cnblogs.com/yuanzfy/archive/2011/08/26/2155189.html)

如果不使用CArchive/CSocketFile,则同步与异步最大的区别在于没有调用系统通知的OnConnect与OnSend。下例采用串行化进行说明。

1、创建基于对话框的MFC项目,包含Windows套接字。在工程中创建基于CSocket的类MySocket用于通信。

1)客户端:在MySocket类中新增函数pGetDlg用户快速获取主窗口指针,并声明一个Dlg类的指针用于绑定,在CXXXDlg.h中声明指针对象m_ClientSocket;

2)服务端:在MySocket类中新增函数pGetDl用户快速获取主窗口指针,并声明一个Dlg类的指针用于实现函数快速获取指针。在CXXXDlg.h中声明指针对象m_ListenSocket/m_ServerSocket。

Tips:相比异步通信,新增了三个指针对象,分别用于收发和缓冲。

 // XXXSocke.h中

 class CXXXDlg;     //类声明,创建指针对象
class XXXSocket : public CSocket
{
public:
CXXXXDlg *m_dlg;
void pGetDlg(CXXXXDlg*dlg); CArchive *m_archiveIn;
CArchive *m_archiveOut;
CSocketFile *m_socketFile;
......
} void CxxxxSocket::pGetDlg(CxxxxDlg* dlg)
{
m_dlg=dlg;
}

2、在Dlg类中对指针对象初始化,并声明通信处理函数

因指定为指针型,在Dlg.cpp的初始化InitInstance函数中中进行指针初始化(=NULL),并新增一个CString变量用于接收信息.

 class CXXXXDlg : public CDialog
{
public:
CXXXXSocket * m_xxxxsocket;  //客户端一个,服务器端两个,一个用于监听,一个用于服务
CArchive *m_archiveIn;
CArchive *m_archiveOut;
CSocketFile *m_socketFile;
CString recvfile; //用于临时接收文件
void OnReceive();
void OnClose();
// void OnConnect();不需要
void Reset(); //用于释放套接字对象
......
}
//在Dlg.cpp中实现Reset函数,即删除套接字对象,并将指针赋空
void CXXXDlg::Reset()
{
  m_XXXXXsocket->Close(); //如果不关闭的话,直接点击中断会引发程序崩溃
 m_ArchiveIn->Close();
  m_ArchiveOut->Close();
 m_socketFile->Close();
if(m_xxxxSocket!=NULL) //注意用于监听的套接字不能释放,因为监听处于打开状态,与连接是并列关系
{
delete m_xxxxSocket;
m_xxxxSocket=NULL;
}
if(m_archiveIn!=NULL)
{
delete m_archiveIn;
m_archiveIn=NULL;
}
if(m_archiveOut!=NULL)
{
delete m_archiveOut;
m_archiveOut=NULL;
}
if(m_socketFile!=NULL)
{
delete m_socketFile;
m_socketFile=NULL; } } void CXXXXDlg::OnBnClickedCancel() //采用指针机制,在退出时需确保指针释放
{
// TODO: 在此添加控件通知处理程序代码
Reset();
OnCancel();
}

3、实例化套接字对象,并更新Dlg.cpp中的函数

1)客户端:在连接时实例化一个Socket对象,并绑定指针到主窗口,创建串行化对象用于接发写;

 void Ccase005Dlg::OnBnClickedBnConnect()
{
// TODO: 在此添加控件通知处理程序代码
if(!AfxSocketInit()) //套接字初始化失败提示
{
MessageBox("windowsocket initial failed ","Receive",MB_ICONSTOP);
return;
}
m_clientsocket=new CMySocket;
m_clientsocket->pGetDlg(this);
m_clientsocket->Create(); BYTE nFild[];
CString strIP;
UpdateData(); m_edit_ip.GetAddress(nFild[],nFild[],nFild[],nFild[]);
strIP.Format("%d.%d.%d.%d",nFild[],nFild[],nFild[],nFild[]); if(!m_clientsocket->Connect(strIP,atoi(m_str_port))) //创建失败提示,异步通信是在网络事件响应时触发nErrorCoe {
AfxMessageBox("连接失败,请您重试!");
return ;
}
else
{
m_listbox.AddString("连接成功!");
// m_listbox.SetTopIndex(m_listbox.GetCount()-1);
m_socketFile=new CSocketFile(m_clientsocket);
m_ArchiveIn=new CArchive(m_socketFile,CArchive::load);
m_ArchiveOut=new CArchive(m_socketFile,CArchive::store); //用于发送写 m_edit_ip.EnableWindow(FALSE);
m_edit_port.EnableWindow(FALSE);
m_bn_connect.EnableWindow(FALSE);
m_bn_disconnect.EnableWindow(TRUE);
m_bn_clear.EnableWindow(TRUE);
m_bn_send.EnableWindow(TRUE);
m_bn_rewrite.EnableWindow(TRUE);
m_editbox.EnableWindow(TRUE);
}
} void Ccase005Dlg::OnBnClickedBnDisconnect()
{
// TODO: 在此添加控件通知处理程序代码
m_listbox.AddString("断开连接!");
Reset(); m_edit_ip.EnableWindow(TRUE);
m_edit_port.EnableWindow(TRUE);
m_bn_connect.EnableWindow(TRUE);
m_bn_disconnect.EnableWindow(FALSE);
m_bn_clear.EnableWindow(TRUE);
m_bn_send.EnableWindow(FALSE);
m_bn_rewrite.EnableWindow(FALSE);
m_editbox.EnableWindow(FALSE);
}

2)服务器端:监听在获取IP地址后,调用Create创建套接字,并侦听连接请求。

 void Ccase006Dlg::OnBnClickedBnListen()
{
// TODO: 在此添加控件通知处理程序代码
if(!AfxSocketInit())
{
MessageBox("Windowsocket initial failed!","Send",MB_ICONSTOP);
return ;
}
m_listensocket=new CMySocket; //创建套接字对象
m_listensocket->pGetDlg(this);
BYTE nFild[];
CString strIP;
UpdateData(); //更新获取数据
m_edit_ip.GetAddress(nFild[],nFild[],nFild[],nFild[]);
strIP.Format("%d.%d.%d.%d",nFild[],nFild[],nFild[],nFild[]);
m_listensocket->Create(atoi(m_str_port),,strIP); //此处的Create是三参数
m_listensocket->Listen();
m_listbox.AddString("监听开始");
m_listbox.AddString("地址"+strIP+" 端口"+m_str_port);
m_listbox.AddString("等待客户端连接...."); } void Ccase006Dlg::OnBnClickedBnStoplisten()
{
// TODO: 在此添加控件通知处理程序代码
m_listensocket->Close();
if(m_listensocket!=NULL)
{
delete m_listensocket;
m_listensocket=NULL;
}
m_listbox.AddString("停止监听");
}

完成OnAccept函数,并调用AsyncSelect准备随时接收信息。

 void Ccase006Dlg::OnAccept(void)
{
m_serversocket=new CMySocket;
m_serversocket->pGetDlg(this);
m_listensocket->Accept(*m_serversocket);
m_serversocket->AsyncSelect(FD_READ|FD_CLOSE); m_socketfile=new CSocketFile(m_serversocket);
m_archiveIn=new CArchive(m_socketfile,CArchive::load);
m_archiveOut=new CArchive(m_socketfile,CArchive::store);
m_listbox.AddString("接收到连接请求");
m_listbox.SetTopIndex(m_listbox.GetCount()-);
}

3)完成其他对应的功能模块:发送信息、接收信息、断开连接、清空列表、重新输入、OnClose、OnReceive。可以通用。

 void Ccase005Dlg::OnBnClickedBnSend()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
*m_ArchiveOut<<m_str_words;
m_ArchiveOut->Flush();
m_listbox.AddString("发送: "+m_str_words);
m_listbox.SetTopIndex(m_listbox.GetCount()-); m_editbox.SetWindowText(""); //注意发送后清空输入内容
m_editbox.SetFocus(); //发送后焦点指定在编辑栏
}
void Ccase005Dlg::OnBnClickedBnRewrite()
{
// TODO: 在此添加控件通知处理程序代码
m_editbox.SetWindowText("");
m_editbox.SetFocus();
} void Ccase005Dlg::OnBnClickedBnClear()
{
// TODO: 在此添加控件通知处理程序代码
m_listbox.ResetContent();
} void Ccase005Dlg::OnReceive(void)
{
*m_ArchiveIn>>recvfile;
m_ArchiveIn->Flush();
m_listbox.AddString("收到: "+recvfile);
m_listbox.SetTopIndex(m_listbox.GetCount()-);
} void Ccase005Dlg::OnClose(void)
{
Reset();
m_listbox.AddString("服务器断开了");
// m_listbox.SetTopIndex(m_listbox.GetCount()-1); m_edit_ip.EnableWindow(TRUE);
m_edit_port.EnableWindow(TRUE);
m_bn_connect.EnableWindow(TRUE);
m_bn_disconnect.EnableWindow(FALSE);
m_bn_clear.EnableWindow(TRUE);
m_bn_send.EnableWindow(FALSE);
m_bn_rewrite.EnableWindow(FALSE);
m_editbox.EnableWindow(FALSE);
}

4 、实现网络事件响应函数

在执行相应按钮操作后,系统会根据程序运行自动触发响应。因采用指针调用机制。所有处理事件的实现已经在主程序体中完成, 使用指针调回主程序接口即可.

 void CMySocket::OnClose(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类
m_dlg->OnClose();
CSocket::OnClose(nErrorCode);
} void CMySocket::OnReceive(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类
m_dlg->OnReceive();
AsyncSelect(FD_READ|FD_CLOSE|FD_WRITE); //需使用此条用于随时接收信息
CSocket::OnReceive(nErrorCode);
}

5、大功告成。

小结:

1) 同步通信与异步通信各有千秋,理解其机制运行;

2)多保存,以免网页程序崩溃;

3)基本操作要烂熟于心。

004之MFCSocket同步编程(指针机制)的更多相关文章

  1. 003之MFCSocket异步编程(指针机制)

    002篇是采用传统方式创建,不适应动态的网络环境,服务器为客户端保留着断开连接时的套接字,不够灵活.而采用指针机制不仅可以更加灵活性,而且能使代码更集中,更具有条理性.将其转变成指针机制.功能及运行保 ...

  2. javaEE开发中使用session同步和token机制来防止并发重复提交

    javaEE开发中使用session同步和token机制来防止并发重复提交 通常在普通的操作当中,我们不需要处理重复提交的,而且有很多方法来防止重复提交.比如在登陆过程中,通过使用redirect,可 ...

  3. boot asio 非阻塞同步编程---非阻塞的accept和receive。

    boot asio 非阻塞同步编程---非阻塞的accept和receive. 客户端编程: #include<boost/timer.hpp> #include <iostream ...

  4. 网络编程基础----并发编程 ---守护进程----同步锁 lock-----IPC机制----生产者消费者模型

    1  守护进程: 主进程 创建 守护进程   辅助主进程的运行 设置进程的 daemon属性 p1.daemon=True 1 守护进程会在主进程代码执行结束后就终止: 2 守护进程内无法再开启子进程 ...

  5. Linux 信号量同步编程

    前一篇文章概述了Linux 系统中信号量互斥编程,这篇文章正好是前一篇的姊妹篇----信号量同步.说它们是姊妹篇是因为它们都是利用了内核的信号量机制实现了进程间的通信.因为两者所解决的问题不同,因此它 ...

  6. Linux环境编程进程间通信机制理解

    一.Linux系统调用主要函数 二.创建进程 1.创建子进程系统调用fork() 2.验证fork()创建子进程效果 3.系统调用fork()与挂起系统调用wait() 三.模拟进程管道通信 四.pi ...

  7. js同步 异步 运行机制

    需要知道的那些事: 1.JS是单线程的(为什么?因为能提高效率.作为浏览器脚本语言,js的主要用途是与用户互动,操作DOM.而这也就决定它只能为单线程,否则会带来很复杂的同步问题),也就是说无法同时执 ...

  8. 【java回调】同步/异步回调机制的原理和使用方法

    回调(callback)在我们做工程过程中经常会使用到,今天想整理一下回调的原理和使用方法. 回调的原理可以简单理解为:A发送消息给B,B处理完后告诉A处理结果.再简单点就是A调用B,B调用A. 那么 ...

  9. Java线程同步的Monitor机制(Lock配合Condition)

    Monitor模式是一种常见的并行开发机制, 一个Monitor实例可以被多个线程安全使用, 所有的monitor下面的方法在运行时是互斥的, 这种互斥机制机制可以用于一些特性, 例如让线程等待某种条 ...

随机推荐

  1. c# Linq&Lambda

    0.写这个文章主要记录下常用Lambda的用法,能力有限,文中有问题的地方希望各位大神指出来谢谢!因为平时写代码的时候没有特地去用lambda,全是用一些循环,少量会用到lambda,虽然也能实现要的 ...

  2. MySQL Transaction--查看未提交事务执行的SQL

    未提交事务 长期未提交事务,指开启事务后,长时间未向MySQL发出SQL执行请求或事务处理(COMMIT/ROLLBACK)请求,在系统表`information_schema`.`INNODB_TR ...

  3. openstack--10--知识点补充

    关于uuid和Fernet方式比较 提供令牌有四种方式[fernet|pkiz|pki|uuid]默认是uuid.

  4. js 中逻辑为 false 的8种情况

    如果对象无初始值或者其值为 数字0.-0.null."".false.undefined 或者 NaN,那么对象的逻辑值为 false. 注意:字符串 '0',值为 true ty ...

  5. C# 生成海报,文本区域指定和换行,图片合成

    protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { string path = Server.MapPa ...

  6. VS 自动展开选中当前代码所在的文件位置的功能

    这个功能相当好,自动在Solution Explorer中展开并定位到当前代码所在的文件,免得自己找位置要找很久. 设置方法: tool>>options>>projects ...

  7. 使用xheditor时 cloneRange错误 ext.net

    使用ext.net 加  xheditor时,一直报 cloneRange错误. 于是 按照说明但独使用xheditor  ,检查无错,正常使用, 因此排除版本问题. <ext:panel ru ...

  8. 网页中HTML代码如何实现字体删除线效果

    有的朋友在制作网站的时候,需要给字体制作删除线,例如:选择题,错误标识等!那么我们就需要用到了<s>这个标签写法如下 字体删除线: <s>这里是内容</s> 效果如 ...

  9. 总结:Java 集合进阶精讲2-ArrayList

    知识点:Java 集合框架图 总结:Java 集合进阶精讲1 总结:Java 集合进阶精讲2-ArrayList 初探: ArrayList底层结构是数组,是List接口的 可变数组的实现,所以会占用 ...

  10. spark2.1源码分析4:spark-network-common模块的设计原理

    spark-network-common模块底层使用netty作为通讯框架,可以实现rpc消息.数据块和数据流的传输. Message类图: 所有request消息都是RequestMessage的子 ...