
MFC对SOCKET编程的支持实际上是足够的,但是其文档尚不清楚. 因此,用VC编写的大多数功能都略有
复杂的网络程序仍使用API. 因此,CAsyncSocket和CSocket实际上变得很困难,而且距离遥远. 我
善行也不能忍受资源的浪费.
首先,CAsyncSocket和CSocket之间的区别
前者是异步通信,后者是同步通信;前者是非阻止模式,后者是阻止模式. 另外,异步非阻塞模式具有
也称为长连接,同步阻止模式称为短连接. 为了使两者之间的区别更加清晰,举一个例子:
假设您是一名体育老师mfc socket 是否无效,并且需要测试100名学生的400米成绩. 当然,您不会让100位同学一起开始,因为什么时候
学生返回终点线时,您没有时间捏桌子记录学生的成绩.
如果让同学每次都开始并等待他返回终点,则写下分数,然后开始下一个分数,直到所有同学都完成. 恭喜你
嗨,您已经掌握了同步阻止模式.
您已经设计了一个函数,输入参数是学生编号和开始时间,返回值是到达终点的时间. 您调用此函数100次,
您可以完成此测验任务. 该函数是同步的,因为只要您调用它,就可以得到结果. 此功能也被阻止,
由于调用它,您必须等到它给出结果后,您才能执行其他操作.
如果让同学每隔10秒从一侧开始,直到所有同学都完成开始;对方的所有其他同学将返回终点线并记录为
成就,直到所有学生都完成跑步. 恭喜,您已经掌握了异步非阻塞模式.
您已经设计了两个功能,其中一个记录开始时间和学生人数,您将主动调用此功能100次;其他功能记录
记录到达时间和学生人数. 此函数是事件驱动的回调函数. 当同班同学到达终点时,您将被被动召唤.
您主动调用的函数是异步的,因为调用它不会告诉您结果;此功能也是非阻塞的,因为您一个
一旦被调用,它将立即返回,您无需等待即可再次调用它. 但是只需调用此函数100次,您就不会完成
进入测验任务,您需要被动地等待另一个函数被调用100次.
当然,您会立即意识到,同步阻塞模式的效率大大低于异步非阻塞模式. 那么,谁将使用同步阻止?
模式如何?
是的,异步模式是有效的,但更麻烦. 您需要记录开始的同学的数据,同时记录到达的同学的数据,并且
学生返回终点线的顺序与开始顺序不同,因此您必须在成绩簿中继续寻找学生编号. 赶紧
在
你通常是张冠理戴.
您可能会想出一种更聪明的方法: 您带来了许多秒表,让学生们在小组中相互测试. 恭喜你!您已经掌握了多行
程序同步模式!
每个拥有秒表的学生都可以独立调用您的同步功能,这不容易出错,只要秒表足够,效率就会大大提高
很多情况下,同步效率也可以达到甚至超过异步.
可以理解,您当前的问题可能是: 由于多线程同步既快速又良好,是否需要异步模式?
不幸的是,异步模式仍然非常重要,因为在很多情况下,您无法获得很多秒表. 您需要与之通信的对等系统可能
仅允许您建立SOCKET连接,这是金融和电信行业中许多大型业务系统所必需的.
现在,您应该已经了解: 当少量连接时,CAsyncSocket用于处理大量非步骤相关的服务. CSocket

用于处理与步骤相关的服务,或者在可能建立多个连接时与多个线程一起使用.
第二个CAsyncSocket异步机制
获得异步连接后,实际上就删除了发送和接收动作之间的依赖关系. 因此您可以随时发送包裹,
您也可以随时收到包裹. 发送和接收功能是异步且无阻塞的,并且可以立即返回,因此发送和接收是交错的,您可以
始终工作并保持高效率. 但是,由于发送和接收功能是异步且非阻塞的,因此无法仅调用它们
确保完成发送或接收. 例如,发送函数“发送”,调用它可能有4种结果:
1. 错误,Send()== SOCKET_ERRORmfc socket 是否无效,GetLastError()!= WSAEWOULDBLOCK,这种情况可能是由各种网络问题引起的
因此,您需要立即决定是放弃此操作还是启用一些对策
2. 忙,Send()== SOCKET_ERROR,GetLastError()!= WSAEWOULDBLOCK,原因是您的发送
缓冲区已满,或另一方的接收缓冲区已满. 您实际上不必立即处理这种情况. 因为CAsyncSocket将
记住您的Send WSAEWOULDBLOCK,要发送的数据将被写入CAsyncSocket内的发送缓冲区中,并且不会忙碌
OnSend被自动调用以在内部缓冲区中发送数据.
3. 部分完成,剩余的0空缺不足以容纳您这次需要发送的所有数据. 解决这种情况的通常方法是继续发送未发送的邮件
数据,直到全部完成或WSAEWOULDBLOCK. 这种情况很容易引起怀疑. 由于缓冲区不为空,这次
缓冲区已满,为什么要继续发送它,就像WSAEWOULDBLOCK已移交给OnSend来处理剩余的一样
发送剩余数据是否更合理?不幸的是,CAsyncSocket不会记住您只是部分完成了发送任务,因此很合适
OnSend在以下时间触发
因为您没有WSAEWOULDBLOCK. 您可能会认为,由于缓冲区已满,它将不可避免地继续发送
WSAEWOULDBLOCK,实际上并非如此. 如果WSAEWOULDBLOCK是由另一方未及时读取接收缓冲区引起的,请继续发送
WSAEWOULDBLOCK很可能是WSAEWOULDBLOCK,但是如果WSAEWOULDBLOCK是由于发送缓冲区已满,则不一定是因为您
网卡处理发送缓冲区中数据的速度可能不慢于将数据复制到发送缓冲区中的速度,这取决于与您的竞争情况
其他应用程序的具体情况是CPU,内存,带宽资源. 如果此时CPU负载大而网卡负载低,虽然
刚发送的缓冲区已满,如果继续发送,将不会发送WSAEWOULDBLOCK.
4. 完成,发送(pBuf,nLen)== nLen
OnResenve,OnConnect,OnAccept将协助接收,连接
就像OnSend协助发送一样完成工作
Accept完成工作. 所有这些都是通过消息机制完成的:
在使用CAsyncSocket之前,必须调用AfxSocketInit初始化WinSock环境,然后AfxSocketInit将创建一个
隐藏的CSocketWnd对象. 由于此对象派生自Cwnd,因此可以接收Windows消息. 这样可以成为高级
CAsyncSocket对象与WinSock底层之间的桥梁. 例如,当CAsyncSocket位于“发送WSAEWOULDBLOCK”中时,它将
将消息作为报告发送给CSocketWnd,当CSocketWnd从基础WinSock收到消息时,它将维护一份报告注册表单.
有空闲消息时,它将检索报告注册表格,然后直接调用报告者的OnSend函数. 因此,上面提到的CAsyncSocket将是
自动调用OnXxx实际上是错误的. 真正的调用者是CSocketWnd-它是一个CWnd对象,在单独的行上运行
在此过程中.

使用CAsyncSocket时,发送过程和接收过程不同. 如果不了解这一点,就不可能顺利使用CAsyncSocket.
MSDN对CAsyncSocket的解释很容易理解: 只有当OnSend触发发送时,它才有意义,您应该发送它,
您还应该仅在触发OnRecieve时接收. 不幸的是,您错了:
您会发现在建立连接时第一次触发了OnSend,嗯,这很好,但是您不想立即发送,请允许OnSend
返回,执行其他操作,然后等待下一次OnSend尝试?实际上,您永远都不能等待触发OnSend. 因为,除了
除了第一次,OnSend的任何触发都是由您调用Send引起的,但是遇到了WSAEWOULDBLOCK!
因此,在使用CAsyncSocket时,发送的流逻辑应为: 您需要两个成员变量,一个需要发送任务表,另一个需要
记录发送进度. 您可以并且应该在需要时主动调用Send发送数据,更新任务表和
发送进度. OnSend是您的助手,负责擦拭屁股. 触发时要做的就是根据任务表发送并发送
发送进度以继续发送. 如果您无法发送所有任务列表,请更新发送进度,退出并等待下一个OnSend;如果
任务表已完全发送,然后清除任务表并发送进度.
使用CAsyncSocket进行接收过程的逻辑是不同的: 您无需主动调用Recieve,而应只使用OnRecieve介质
等等. 由于您不知道将要到达的数据的类型和顺序,因此需要将接收到的数据表定义为要存储的成员变量
已接收但尚未处理的数据. 每次触发OnRecieve时,您只需被动调用一次Recieve即可接受定长数据,
并将其添加到您收到的数据表中. 然后,您需要扫描收到的数据表(如果它包含一个或几个完整的可分析业务)
数据包被截获,业务处理窗口的处理功能被调用进行处理或作为消息参数发送到业务处理窗口. 并收到
根据表中的剩余数据,我们将等待下一个OnRecieve进行合并,扫描和再次处理.
在长连接应用程序中,由于各种原因,连接可能会中断,因此您需要自动重新连接. 您需要根据CAsyncSocket的成员进行更改
使用m_hSocket确定当前连接状态: if(m_hSocket == INVALID_SOCKET). 当然,即使已经建立连接也很奇怪
中断,还触发了OnClose,您仍然需要在OnClose中主动调用Close,否则m_hSocket将不会自动分配
INVALID_SOCKET.
在许多长连接应用程序中,除了建立连接之外,还需要登录才能执行业务处理. 连接和登录是一个步骤
突然的依赖性处理,异步处理将非常麻烦,并且CAsyncSocket支持切换到同步模式,您应该掌握它
在适当的情况下在相同和异步模式之间切换的方法:
DWORD dw;
//切换到同步模式
dw = 0;
IOCtl(FIONBIO,&dw);
...
//切换回异步模式
dw = 1;
IOCtl(FIONBIO,&dw);
三,CSocket的用法
基于CAsyncSocket,CSocket修改了诸如发送和接收之类的成员函数,以帮助您构建用于轮询发送和接收的缓冲区

周期
成为同步短连接模式.
短连接应用程序简单明了. CSocket通常可以直接使用而无需派生,但是存在一些问题:
1. 用于监视时
我已经看到有人自己创建一个线程,在该线程中为侦听和接受创建一个CSocket对象,如果接受成功,则开始新的一行
Cheng继续聆听并接受. . . 可以说他根本不了解CSocket. 实际上,CSocket的监视机制具有内置的多线程计算机
控件,您只需要从CSocket派生然后重新加载OnAccept:
// CListenSocket头文件
CListenSocket类: 公共CSocket
{
公开
:
CListenSocket(HWND hWnd = NULL);
HWND m_hWnd; //事件处理窗口
虚拟无效OnAccept(int nErrorCode);
};
// CListenSocket实现文件
#include“ ListenSocket.h”
CListenSocket :: CListenSocket(HWND hWnd){m_hWnd = hWnd;}
void CListenSocket :: OnAccept(int nErrorCode)
{
SendMessage(m_hWnd,WM_SOCKET_MSG,SOCKET_CLNT_ACCEPT,0);
CSocket :: OnAccept(nErrorCode);
}
//主线程
...
m_pListenSocket =新的CListenSocket(m_hWnd);
m_pListenSocket-> Create(...);
m_pListenSocket-> Listen();
...
LRESULT CXxxDlg :: OnSocketMsg(WPARAM wParam,LPARAM lParam)
{
UINT类型=(UINT)wParam;
开关(类型)

{
SOCKET_CLNT_ACCEPT:
{
CSocket * pSocket =新的CSocket;
if(!m_pListenSocket-> Accept(* pSocket))
{
删除pSocket;
休息;
}
...
}
...
}
}
2. 用于多线程
我经常看到人们说CSocket不能在子线程中使用,但事实并非如此. 实际情况是:
直接使用CSocket动态创建的对象,并将其指针作为参数传递给子线程,然后完成所有操作,例如在子线程中进行发送和接收
没问题. 但是,如果它是使用CSocket派生类创建的对象,则取决于您重载了哪些方法,如果您仅重载了OnClose,
您可以在子线程中正常发送和接收,但无法关闭!
因为CSocket与内部循环同步并且不依赖于OnXxx,所以它不需要与CSocketWnd交互. 但是当您获得相等的权重
在加载OnXxx之后,它必须与CSocketWnd交互才能提供消息机制. 当您调用AfxSocketInit时,您的主线程将获得
获取用于访问CSocketWnd的句柄. MFC自动完成对CSocketWnd的访问,并被隐藏. 您可以自己创建
的子线程
不会自动具有访问CSocketWnd的机制,因此需要在子线程中访问CSocketWnd的操作将失败.
常见的解决方案是将SOCKET句柄传递给子线程而不是CSocket对象指针,然后在子线程中创建一个CSocket临时对象
由Attach传递的对象和句柄. 使用后,请删除并删除临时对象. 我以前没做过这,可能是因为Attach方法
包含用于获取CSocketWnd句柄的内置函数.
我的解决方案仍然使用自定义消息. 例如,我无法在子线程中关闭,因此我可以向主线程发送一条消息,
让主线程的消息处理功能完成关闭也很方便.
CSocket通常与多个线程一起使用. 只要您要发送和接收数据,就可以创建一个CSocket对象并创建一个子线程
发送和接收. 因此,只有子线程被阻塞,主线程始终可以创建一个子线程来帮助其工作. 因为可能同时有很多
多个CSocket对象正在工作,因此通常必须创建一个列表来存储这些CSocket对象的标识,因此您可以通过
检索列表中的标识符以区分每个CSocket对象. 当然,由于内存地址的唯一性,对象指针本身可以用作标识符.
与CAsyncSocket相比,CSocket的操作过程更加直观,简单. 至于CSocketFile,CArchive等,看来
您无需说什么,只需结束.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-236396-1.html
最后的笑脸帅啊
多少算是低收入
来了
成功了