首页 > 其他 > 详细

Socket重叠IO

时间:2015-10-01 00:28:25      阅读:424      评论:0      收藏:0      [点我收藏+]

1.为什么到现在才弄懂这个

不知道这个Socket重叠IO这种模型是不是socket IO完成端口的基础,不过我感觉,学习一下这个再去学习socket IO完成端口是比较有好处的。

这个Scoket重叠IO我以前记得看过好几次,都没看懂。一部分原因是我没能静态心来写代码,还有更重要的原因就是,Socket重叠他们的结构体参数,还有传参数让人很难理解。下面我将对这些数据结构和参数进行一下讲解

2.初识WSARecv 函数

 

int WSARecv(
        SOCKET s,//要接收消息的socket
        LPWSABUF lpBuffers, //一个结构体数组。当接收IO操作完毕后接收内容就在这个里面了
        DWORD dwBufferCount, //要接多少个WSABUF
        LPDWORD lpNumberOfBytesRecvd,//接收了多少个字节
        LPDWORD lpFlags,
        LPWSAOVERLAPPED lpOverlapped,//Overlapped结构体指针
        LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine//在本节用不用
        );

lpBuffers参数:这是一WSABUF数组,意思是这个函数可以接收不止一个字符缓冲,但是我们一般用一个就够了。 接收多个我还没能测试

dwBufferCount参数:是指上一个参数的数组个数

lpOverlapped参数:这个参数是Overlappad结构体指针,这个指针当IO操作完毕的时候,这里会被系统填充。当IO操作完成时这个结构也可以通过WSAGetOverlappedResult得到

返回值:

0:没有错误发生,IO操作当即完成

SOCKET_ERROR:发生错误

如果是SOCKET_ERROR并且WSAGetLastError() == WSA_IO_PENDING 这时表示操作已经提交。异步操作大部分都是这样的。

3.何时得到收取的消息,然后取出消息

当异常操作完成时,Overlapped的hEvent这个事件会触发。这时Overlapped的InternalHigh表示接受的字节数。Internal表示错误代码。消息的内容即是你当初调用WSARecv时传入的lpBuffers参数。

4.代码组织

以服务端为例

首先传入WSARecv的几个参数必定与一个socket关联。而且这些参数在异步调用完成之后,但是以后还要用(在WaitForMutiObjects时要用到),而且每一个socket得拥有一个不同的Event来标识是哪个客户端来消息了。所以为每一个客户端socket构造一个Overlapped结构。比如我测试的代码中每一个客户端都有这样一个结构体,而且当accept来的时候表示有新的socket连接,就得生成这样一个结构体,当客户端掉线的时候,就得删除这样一个结构体

下面就是这个结构体:

struct CClientInfo
{
public:
    CClientInfo() 
    {
        ZeroMemory(&m_ol,sizeof(m_ol));
        ZeroMemory(m_szBuf,256);
        m_ol.hEvent = WSACreateEvent();
    }
    ~CClientInfo()
    {
        WSACloseEvent(m_ol.hEvent);
    }
    WSAOVERLAPPED m_ol;
    SOCKET sSocket;
    CString strIp;
    u_short nPort;
    CString GetShowText();
    char m_szBuf[256];
};

 

下面是两个函数,一个是当客户端连接的时候,一个是当客户端断开的时候

CClientInfo * CServerDlg::OnSocketConnected(SOCKET sClientSocket,sockaddr_in * saClient)
{
    u_short uPort =  ntohs(((sockaddr_in *)saClient)->sin_port);
    CString strIp = CA2T(inet_ntoa(((sockaddr_in *)saClient)->sin_addr));
    CClientInfo * pClientInfo = new CClientInfo;
    pClientInfo->nPort = uPort;
    pClientInfo->strIp = strIp;
    pClientInfo->sSocket = sClientSocket;
    LockClientArray();
    m_ClientArray.Add(pClientInfo);
    int nIndexInserted = m_ClientListBox.AddString(pClientInfo->GetShowText());
    m_ClientListBox.SetItemData(nIndexInserted,pClientInfo->sSocket);
    UnLockClientArray();
    return pClientInfo;
}

void CServerDlg::OnSocketDisconnect(SOCKET aClientSocket)
{
    LockClientArray();
    for(int i = 0;i<m_ClientArray.GetCount();i++)
    {
        CClientInfo * pClientInfo = m_ClientArray.GetAt(i);
        if(pClientInfo->sSocket == aClientSocket)
        {
            m_ClientListBox.DeleteString(m_ClientListBox.FindString(0,pClientInfo->GetShowText()));
            delete pClientInfo;
            m_ClientArray.RemoveAt(i);
            break;
        }
    }
    UnLockClientArray();
}

5.没有测试的内容和疑问

如果WSARecv调用两次会是什么情况,有没有影响。

我没有用异步AcceptEx,感觉这个函数异步了,作用也不大,以后如果需要的话,再学习吧

发送的时候没有用WSASend,以后再学习

Socket重叠IO

原文:http://www.cnblogs.com/zhangdongsheng/p/4850533.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!