吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4812|回复: 3
收起左侧

[会员申请] 申请ID:zyq8709[申请通过]

 关闭 [复制链接]
吾爱游客  发表于 2011-5-15 22:05
1、ID:zyq8709/zyqqyz
2、邮箱:zyq8709@163.com
3、特长:熟悉并爱好c/c++,asm,sdk,mfc,驱动,逆向,破解等底层和黑客技术,发现贵论坛资源丰富高手如云,故想申请一账号和大家交流学习,希望管理员批准,刚才发过一遍,但未看要求不合格,故重发一遍。
附上我在看雪上申请会员的原创帖(已通过申请)
链接:http://bbs.pediy.com/showthread.php?t=130688
全文如下:
注:本文适合有一定Winsock编程和mfc编程基础的朋友阅读。
我是一个对一切事情都爱探究到底的人,前一段由于需要使用mfc开发一个网络通信程序,于是就顺便研究了一下CSocket类的工作工程,现将我的一些学习成果公布出来,希望大家多多指正。
先看CSocket的create函数,它调用了基类CAsyncSocket::Create函数,下面跟进去看到
BOOL CAsyncSocket::Create(UINT nSocketPort, int nSocketType,
    long lEvent, LPCTSTR lpszSocketAddress)
{
    if (Socket(nSocketType, lEvent))
    {
        if (Bind(nSocketPort,lpszSocketAddress))
            return TRUE;
        int nResult = GetLastError();
        Close();
        WSASetLastError(nResult);
    }
    return FALSE;
}
先调用Socket函数,在此函数中先调用api函数socket创建一个套接字并返回给m_hSocket,如果创建成功就进行CAsyncSocket::AttachHandle,实现套接字句柄与CSocket类对象的绑定,在绑定函数中创建了一个CSocketWnd对象,并创建一个窗口但并不显示,我称之为socket窗口,在创建之前有个判断pState->m_pmapSocketHandle->IsEmpty(),作用是检查socket的绑定映射是否为空,如果是空就不再创建socket窗口了,目的是节省资源,也就是保证只有一个socket窗口。socket窗口用于接收网络消息,并处理消息响应。接下来调用CAsyncSocket::AsyncSelect函数,其中又调用了WSAAsyncSelect函数,创建异步套接字,即当一些网络行为发生时向socket窗口发送WM_SOCKET_NOTIFY消息,然后消息处理程序在进行分类处理。这是CSocket类工作的核心。 这里注册了这些事件FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,详细含义大家可参考msdn。即这鞋事件发生时向socket窗口发送WM_SOCKET_NOTIFY消息。接下来的Bind函数无非就是做一些初始化并调用api函数bind,如果有一些基础大家都能明白。如果出错就关闭套接字,成功就返回。
接下来按标准过程就该监听调用CSocket::Listen函数,此函数很简单,就是调用api函数listen。
下面我来说核心的另一方面,消息处理过程。socket窗口接到WM_SOCKET_NOTIFY消息,根据消息映射,调用CSocketWnd::OnSocketNotify,其中调用静态函数CSocket::ProcessAuxQueue,经过一些判断保护,调用了CAsyncSocket::DoCallBack,同样他也是个静态函数。
这个函数最关键,我把代码放上来。详细解释我放在注释里。
void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
{
    if (wParam == 0 && lParam == 0)
        return;

        CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE);//根据WM_SOCKET_NOTIFY消息的wParam参数寻找对应CSocket对象,这是一个保护,如果对象为空直接返回。因为在异步模式下,每发出一回动作,就会发出WM_SOCKET_NOTIFY消息,如果连续发出读操作,然后关闭套接字。那么当处理多余的消息时套接字已不存在,那么就直接返回。

        if (pSocket != NULL)
        return;

    pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE);
    if (pSocket == NULL)
    {
                pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE);
        ASSERT(pSocket != NULL);

        if(pSocket == NULL)
            return;

        pSocket->m_hSocket = (SOCKET)wParam;
        CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE);
        CAsyncSocket::AttachHandle(pSocket->m_hSocket, pSocket, FALSE);
    }

    int nErrorCode = WSAGETSELECTERROR(lParam);
    switch (WSAGETSELECTEVENT(lParam))//根据lParam的内容分类处理不同事件的操作,并在其中调用程序员自己编写的处理函数如OnReceive等。
    {
    case FD_READ:
        {
            fd_set fds;
            int nReady;
            timeval timeout;

            timeout.tv_sec = 0;
            timeout.tv_usec = 0;

            FD_ZERO(&fds);
            FD_SET(pSocket->m_hSocket, &fds);
            nReady = select(0, &fds, NULL, NULL, &timeout);
            if (nReady == SOCKET_ERROR)
                nErrorCode = WSAGetLastError();
            if ((nReady == 1) || (nErrorCode != 0))
                pSocket->OnReceive(nErrorCode);
        }
        break;
    case FD_WRITE:
        pSocket->OnSend(nErrorCode);
        break;
    case FD_OOB:
        pSocket->OnOutOfBandData(nErrorCode);
        break;
    case FD_ACCEPT:
        pSocket->OnAccept(nErrorCode);
        break;
    case FD_CONNECT:
        pSocket->OnConnect(nErrorCode);
        break;
    case FD_CLOSE:
        pSocket->OnClose(nErrorCode);
        break;
    }
}

在CSocket::Accept函数即接受连接函数中,就是调用api函数accept这么简单。
下面一点也比较关键,也就是在异步套接字中进行操作recevie等操作时如何实现同步即阻塞。
看代码:
int CSocket::Receive(void* lpBuf, int nBufLen, int nFlags)

{

//m_pbBlocking是CSocket的成员变量,用来标识当前是否正在进行

//阻塞操作。但不能同时进行两个阻塞操作。

if (m_pbBlocking != NULL)

{

WSASetLastError(WSAEINPROGRESS);

return FALSE;

}

//完成数据读取

int nResult;

while ((nResult = CAsyncSocket::Receive(lpBuf, nBufLen, nFlags))

== SOCKET_ERROR)

{

if (GetLastError() == WSAEWOULDBLOCK)

{

//进入消息循环,等待网络事件FD_READ

if (!PumpMessages(FD_READ))

return SOCKET_ERROR;

}

else

return SOCKET_ERROR;

}

return nResult;

}
Receive函数首先判断当前CSocket对象是否正在处理一个阻塞操作,如果是,则返回错误WSAEINPROGRESS;否则,开始数据读取的处理。读取数据时,如果基类CAsyncSocket的Receive读取到了数据,则返回;否则,如果返回一个错误,而且错误号是WSAEWOULDBLOCK,则表示操作阻塞,于是调用PumpMessage进入消息循环等待数据到达(网络事件FD_READ发生)。数据到达之后退出消息循环,再次调用CAsyncSocket的Receive读取数据,直到没有数据可读为止。PumpMessages函数中其实就是不断调用PeekMessage函数,直到取到希望的消息时返回。
当CSocket对象析构时会自动调用Close函数关闭套接字或主动关闭。其实其中调用的是CAsyncSocket::Close,又调用CAsyncSocket::KillSocket,其中又调用CAsyncSocket::DetachHandle将对象与套接字分离,并关闭套接字。
好吧,这些已经将CSocket类讲的差不多了,其中的几个关键点也讲明白了,希望大家多多关注,谢谢大家的支持,初次写文章,希望大家多多谅解。

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2011-5-20 19:15
ID:zyq8709
邮箱:zyq8709@163.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息  
Cracker_lang 发表于 2011-5-21 00:38
zyq8709 发表于 2011-5-22 11:25
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 09:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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