郁金香外挂技术-郁金香灬老师

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

郁金香终身VIP管理员QQ150330575项目合作(有实力的+)视频教程+每月更新+QQ群
飞郁视频分享(每周更新)
查看: 216|回复: 0

CAsyncSocket C++套接字

[复制链接]
发表于 2019-7-2 17:12:24 | 显示全部楼层 |阅读模式
PumpMessage会遇到下面几种情况:
1 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_XXX事件,返回True.
2 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_Close事件,返回True.
3 提取出了(从消息队列中移出来Remove),PumpMessage(..)设定的定时器的WM_TIMER消息,TimeOut事件为 CSocket的一个成员变量,m_nTimeOut=2000ms,返回True
4 用户调用了CancelBlockingCall() 设置错误代码为WSAEINTR(被中断了),返回False
5 用户一直没有取到用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的FD_XXX事件,但是取到了同一个线程中的其他Socket的WM_SOCKET_NOTIFY消息及其对应的消息,则将这些消息,加入到一个辅助性的队列中去,以后处理.
6 没有取到任何WM_SOCKET_NOTIFY消息,则开始查看(不是取出来,而是查看)本线程的消息队列中是否有其它消息,如果有的话,调用虚函数OnMessagePending(),来处理这些消息(OnMessagePending()用户可以自定义。在阻塞时,用户想要处理的消息),如果没有,则调用WaitMessage()开始等待消息的到来.

说明[url=]编辑[/url]
代码说明如下:
A 先看Connect,因为Connect的阻塞的实现和Accept,Receive,ReceiveFrom,Send,SendTo都有点不同.
也许你们会奇怪为何是ConnectHelper(...),而不是Connect(...).其实ConnectHelper(...)才是Connect(..)

调用[url=]编辑[/url]
真正调用的东西,如下:
BOOL CAsyncSocket::Connect(const SOCKADDR* lpSockAddr,int nSockAddrLen)
{
return ConnectHelper(lpSockAddr,nSockAddrLen);
}
//ConnectHelper(...)为一虚函数
//继承自CAsyncSocket,Csocket有重新定义过.
//这也是为什么CSocket是Public继承的原因
BOOL CSocket::ConnectHelper(...)
{
//一旦调用 就先检查当前是否有一个阻塞操作正在进行
//如果是,立马返回,并设置错误代码.
......
......
m_nConnectError = -1;
//注意它只调用了一次CAsyncSocket::ConnectHelper(...)
if(!CAsyncSocket::ConnectHelper(...))
{
//由于Connect(...)要求自己和Server进行三步握手
//即需要发送一个Packet,而且等待回复(这个也就是
//涉及连接和发送数据操作的Socket API会阻塞的原因)
//所以CAsyncSocket::ConnectHelper(...)会立即返回,
//并且设置错误为WSAEWOULDBLOCK(调用该函数会导致阻塞)
if(WSAGetLastError() == WSAEWOULDBLOCK)
{
//进入消息循环,以从线程消息队列里查看FD_CONNECT消息,
//收到FD_CONNECT消息(在PumpMessage中会修改m_nConnectError),返回
//或者WM_TIMER/FD_CLOSE(return true,但不会修改m_nConnectError),
//继续调用PumpMessage来取消息
//或者错误,那么就返回socket_error
while(PumpMessages(FD_CONNECT))
{
if (m_nConnectError != -1)
{
WSASetLastError(m_nConnectError);
return (m_nConnectError == 0);
}
} //end while
}
return false;
}
return true;
}
//在PumpMessages中会设置一个定时器,时间为m_nTimeOut=2000ms
//当在这个时间之内,依然没有得到消息的话,就返回
BOOL CSocket:umpMessages(UINT uStopFlag)
{
//一旦进入这个函数,就设置Socket当前状态为阻塞
BOOL bBlocking = TRUE;
m_pbBlocking = &bBlocking;
....................
.....................
....................
CWinThread* pThread = AfxGetThread();
//bBlocking是一个标志,
// 用来判断用户是否取消对Connect()的调用
//即是否调用CancelBlockingCall()
while(bBlocking)
{
//#define WM_SOCKET_NOTIFY 0x0373
//#define WM_SOCKET_DEAD 0x0374
MSG msg;
//在此处只是取WM_SOCKET_NOTIFY 和WM_SOCKET_DEAD消息
if (::PeekMessage(&msg,pState->m_hSocketWindow,WM_SOCKET_NOTIFY,WM_SOCKET_DEAD,
PM_REMOVE))
{
if (msg.message == WM_SOCKET_NOTIFY && (SOCKET)msg.wParam == m_hSocket)
{
//这个是PumpMessage的第2种情况
if (WSAGETSELECTEVENT(msg.lParam) == FD_CLOSE)
{ break;}
//这个是PumpMessage的第1种情况
if(WSAGETSELECTEVENT(msg.lParam) == uStopFlag)
{ ......; break;}
}
//这个是PumpMessage的第5种情况
if (msg.wParam != 0 || msg.lParam != 0)
CSocket::AuxQueueAdd(msg.message,msg.wParam,msg.lParam);
}
//这个是PumpMessage的第3种情况
else if (::PeekMessage(&msg,pState->m_hSocketWindow,WM_TIMER,WM_TIMER,PM_REMOVE))
{ break;}
//这个是PumpMessage的第6种情况
if (bPeek && :eekMessage(&msg,NULL,0,0,PM_NOREMOVE))
{
if (OnMessagePending())
{
}
else
{
// 等待消息的到来
WaitMessage();
.....
}
}
}//end while
////这个是PumpMessage的第4种情况
if (!bBlocking)
{
WSASetLastError(WSAEINTR);
return FALSE;
}
m_pbBlocking = NULL;
//将WM_SOCKET_NOTIFY消息发送到Creat CSocketWnd线程的消息队列
//以便处理其他的Socket消息
::PostMessage(pState->m_hSocketWindow,WM_SOCKET_NOTIFY,0,0);
return TRUE;
}
B 再看Receive(..)
//其实CSocket的这种实现方式决定了,应用程序不能够在一个线程中Create一个socket,
//然后创建一个新的线程来专门Receive,因为这个新的线程将永远不能取到FD_Read的事件,
//因为并不是在这个线程中创建的CSocketWnd对象,它无法接受到发送到CSocketWnd的消息
//(在Windows中接受消息的主体是窗口)
//Receive和Connect的实现方式的最大区别为
//Connect 是不断的调用PumpMessage(..)
//而Receive则不断的调用自身
int CSocket::Receive(void* lpBuf,int nBufLen,int nFlags)
{
if (m_pbBlocking != NULL)
{
WSASetLastError(WSAEINPROGRESS);
returnFALSE;
}
int nResult;
while ((nResult = CAsyncSocket::Receive(lpBuf,nBufLen,nFlags)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK)
{
//一旦提取到FD_READ///FD_CLOSE///WM_TIMER时
// 就再次调用CAsyncSocket::Receive(...)
if (!PumpMessages(FD_READ))
return SOCKET_ERROR;
}
else
return SOCKET_ERROR;
}
return nResult;
}

总结[url=]编辑[/url]
CSocket模式与socket API模式的最大区别在于它实现了:
1、将socket事件消息化
2、用消息阻塞方式实现同步
3、用序列化方式读写数据以防止死锁,简化读取数据模型(流数据)。
多线程编程时,由于CSocket不能跨线程使用,所以,新建工作线程中会有一个CSocket对象,而该对象会重新与已知SOCKET句柄重新Attach,实现在新的线程中以CSocket对象的方式编程。
然后使用消息通信的方式,实现在新建线程中读写数据。
通过消息、线程事件等同步机制 实现UI线程与CSocket对象所在工作线程的通信,并不会影响UI的响应。
在BOOL CSocket:umpMessages(UINT uStopFlag)中
[size=1em]
[size=1em]1

[size=1em]2

[size=1em]3

[size=1em]4

[size=1em]5

[size=1em]6

[size=1em]7

[size=1em]8

[size=1em]9

[size=1em]10

[size=1em]11

[size=1em]12

[size=1em]13

[size=1em]14

[size=1em]15

[size=1em]16

[size=1em]17

[size=1em][size=1em]//...
[size=1em]if(bPeek&&::
[size=1em]PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
[size=1em]{
[size=1em]if(OnMessagePending())
[size=1em]{//
[size=1em]//allowuser-interfaceupdates
[size=1em]ASSERT(
[size=1em]pThread);
[size=1em]pThread->OnIdle(-1);
[size=1em]}
[size=1em]else
[size=1em]{
[size=1em]bPeek=FALSE;
[size=1em]}
[size=1em]}
[size=1em]//...



看OnMessagePending:
[size=1em]
[size=1em]1

[size=1em]2

[size=1em]3

[size=1em]4

[size=1em]5

[size=1em]6

[size=1em]7

[size=1em]8

[size=1em]9

[size=1em]10

[size=1em]11

[size=1em]12

[size=1em]13

[size=1em]14

[size=1em]15

[size=1em]16

[size=1em][size=1em]BOOLCSocket::OnMessagePending()
[size=1em]{
[size=1em]MSGmsg;
[size=1em]if(::
[size=1em]PeekMessage(&msg,NULL,WM_PAINT,WM_PAINT,PM_REMOVE))
[size=1em]{//重新处理当前线程所有窗口的
[size=1em]WM_PAINT消息,
[size=1em]::
[size=1em]DispatchMessage(&msg);//重新派送
[size=1em]returnFALSE;
[size=1em]//usuallyreturnTRUE,butOnIdleusuallycausesWM_PAINTs
[size=1em]//(通常返回TRUE,就会导致OnIdle被执行,但是OnIdle通常导致多次
[size=1em]WM_PAINT消息)
[size=1em]}
[size=1em]returnFALSE;
[size=1em]}




郁金香外挂教程,学习中...
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

限时限量优惠

QQ|小黑屋|手机版|郁金香外挂技术-郁金香灬老师 ( 苏ICP备10059359号 )

GMT+8, 2019-7-24 09:07 , Processed in 0.052790 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表