本人正在学IOCP,去codeproject 上找了一个简单的IOCP模型代码!!
他的代码比较干净,对异常什么的没做太多的处理,比较好理解!看了几遍后,对大部分的实现和工作方式有了一定的了解了!可是,现在对他的工作者线程处理,还是有些不太明白!!下面给他说的全部工作者线程代码:我先说下,这个工作者线程做的是什么吧!这个服务器,道先是接收客户端的数据,然后再把这个数据原封不动的,再发回给客户端.
并等待客户端的断开通知, 就是这么简单的一个服务器!!他把那个结构体定义成了一个类:class CClientContext  //To store and manage client related information
{
private: OVERLAPPED        *m_pol;
WSABUF            *m_pwbuf; int               m_nTotalBytes;
int               m_nSentBytes; SOCKET            m_Socket;  //accepted socket
int               m_nOpCode; //will be used by the worker thread to decide what operation to perform
char              m_szBuffer[MAX_BUFFER_LEN];public:   //public里是一些Set,Get方法;
}
下面是工作者线程代码:
//Worker thread will service IOCP requests
DWORD WINAPI WorkerThread(LPVOID lpParam)
{    
int nThreadNo = (int)lpParam; void *lpContext = NULL;
OVERLAPPED       *pOverlapped = NULL;
CClientContext   *pClientContext = NULL;
DWORD            dwBytesTransfered = 0;
int nBytesRecv = 0;
int nBytesSent = 0;
DWORD             dwBytes = 0, dwFlags = 0; //Worker thread will be around to process requests, until a Shutdown event is not Signaled.
while (WAIT_OBJECT_0 != WaitForSingleObject(g_hShutdownEvent, 0))          //等待服务器退出事件
{
BOOL bReturn = GetQueuedCompletionStatus(
g_hIOCompletionPort,
&dwBytesTransfered,
(LPDWORD)&lpContext,
&pOverlapped,
INFINITE); if (NULL == lpContext)
{
//We are shutting down
break;
} //Get the client context
pClientContext = (CClientContext *)lpContext; if ((FALSE == bReturn) || ((TRUE == bReturn) && (0 == dwBytesTransfered)))
{
//Client connection gone, remove it.
RemoveFromClientListAndFreeMemory(pClientContext);
continue;
} WSABUF *p_wbuf = pClientContext->GetWSABUFPtr();
OVERLAPPED *p_ol = pClientContext->GetOVERLAPPEDPtr();                //上面还真的没什么,问题就在这里,switch这两个操作,一个是读一个是写!
switch (pClientContext->GetOpCode())
{
case OP_READ: pClientContext->IncrSentBytes(dwBytesTransfered); //Write operation was finished, see if all the data was sent.
//Else post another write.
if(pClientContext->GetSentBytes() < pClientContext->GetTotalBytes())
{
                                pClientContext->SetOpCode(OP_READ); p_wbuf->buf += pClientContext->GetSentBytes();
p_wbuf->len = pClientContext->GetTotalBytes() - pClientContext->GetSentBytes(); dwFlags = 0; //Overlapped send
                                //我的问题在这个IF里,那个else里也好理解,就是这个IF里, 这个明明是个读操作嘛OP_READ,可是为什么这里还要WSASend发数据呢???
nBytesSent = WSASend(pClientContext->GetSocket(), p_wbuf, 1, 
&dwBytes, dwFlags, p_ol, NULL); if ((SOCKET_ERROR == nBytesSent) && (WSA_IO_PENDING != WSAGetLastError()))
{
//Let's not work with this client
RemoveFromClientListAndFreeMemory(pClientContext);
}
}
else
{
//Once the data is successfully received, we will print it.
pClientContext->SetOpCode(OP_WRITE);
pClientContext->ResetWSABUF(); dwFlags = 0; //Get the data.
nBytesRecv = WSARecv(pClientContext->GetSocket(), p_wbuf, 1, 
&dwBytes, &dwFlags, p_ol, NULL); if ((SOCKET_ERROR == nBytesRecv) && (WSA_IO_PENDING != WSAGetLastError()))
{
WriteToConsole("\nThread %d: Error occurred while executing WSARecv().", nThreadNo); //Let's not work with this client
RemoveFromClientListAndFreeMemory(pClientContext);
}
} break; case OP_WRITE:
                        //这个OP_WRITE 比较好理解, 它定义一下字符数组,把客户端发来的数据装到这个数组里,再发回给客户端.
char szBuffer[MAX_BUFFER_LEN]; //Display the message we recevied
pClientContext->GetBuffer(szBuffer); WriteToConsole("\nThread %d: The following message was received: %s", nThreadNo, szBuffer); //Send the message back to the client.
pClientContext->SetOpCode(OP_READ);
pClientContext->SetTotalBytes(dwBytesTransfered);
pClientContext->SetSentBytes(0); p_wbuf->len  = dwBytesTransfered; dwFlags = 0; //Overlapped send
nBytesSent = WSASend(pClientContext->GetSocket(), p_wbuf, 1, 
&dwBytes, dwFlags, p_ol, NULL); if ((SOCKET_ERROR == nBytesSent) && (WSA_IO_PENDING != WSAGetLastError()))
{
WriteToConsole("\nThread %d: Error occurred while executing WSASend().", nThreadNo); //Let's not work with this client
RemoveFromClientListAndFreeMemory(pClientContext);
} break; default:
//We should never be reaching here, under normal circumstances.
break;
} // switch
} // while return 0;
}
 我的问题就是,那个读操作,为什么还要WSASend呢???
  这是为什么呢?希望各位朋友给出指点,谢谢!!!

解决方案 »

  1.   

    就是接到数据然后调用 WSASend  在吧数据返还回去嘛!!
      

  2.   

    pClientContext->IncrSentBytes(dwBytesTransfered);            //Write operation was finished, see if all the data was sent.
                //Else post another write.
                if(pClientContext->GetSentBytes() < pClientContext->GetTotalBytes())
                {
                                    pClientContext->SetOpCode(OP_READ);                p_wbuf->buf += pClientContext->GetSentBytes();
                    p_wbuf->len = pClientContext->GetTotalBytes() - pClientContext->GetSentBytes();                dwFlags = 0;                //Overlapped send
                                    //我的问题在这个IF里,那个else里也好理解,就是这个IF里, 这个明明是个读操作嘛OP_READ,可是为什么这里还要WSASend发数据呢???
                    nBytesSent = WSASend(pClientContext->GetSocket(), p_wbuf, 1, 
                        &dwBytes, dwFlags, p_ol, NULL);                if ((SOCKET_ERROR == nBytesSent) && (WSA_IO_PENDING != WSAGetLastError()))
                    {
                        //Let's not work with this client
                        RemoveFromClientListAndFreeMemory(pClientContext);
                    }
                }
                else
                {
                    //Once the data is successfully received, we will print it.
                    pClientContext->SetOpCode(OP_WRITE);
                    pClientContext->ResetWSABUF();                dwFlags = 0;                //Get the data.
                    nBytesRecv = WSARecv(pClientContext->GetSocket(), p_wbuf, 1, 
                        &dwBytes, &dwFlags, p_ol, NULL);                if ((SOCKET_ERROR == nBytesRecv) && (WSA_IO_PENDING != WSAGetLastError()))
                    {
                        WriteToConsole("\nThread %d: Error occurred while executing WSARecv().", nThreadNo);                    //Let's not work with this client
                        RemoveFromClientListAndFreeMemory(pClientContext);
                    }
                }            break;
    我分析如下:
    当收到客户端的数据的时候长度都保存在GetTotalBytes里面,当每发送一部分返回后pClientContext->IncrSentBytes(dwBytesTransfered);增加发送出去的数据,然后在缓冲区buf中增加已经发送的的字节长度的大小,这个时候就到了还没有发动的缓冲区地方,就提交一个OP_READ再次提交一个IO操作,直到if(pClientContext->GetSentBytes() < pClientContext->GetTotalBytes())
    不成立,这个时候再次提交一个接收数据的IO请求。
      

  3.   

    这是IOCP的机制
    正常情况下
    WSARecv,发生OP_READ表示已经接受到数据 或 有数据到来(当提交的WSABUF.len=0时)
    WSASend,发生OP_WRITE表示已经发送了数据这里的WSASend对应OP_READ,WSARecv对应OP_WRITE,反了,真费解
    //我的问题在这个IF里,那个else里也好理解,就是这个IF里, 这个明明是个读操作嘛OP_READ,可是为什么这里还要WSASend发数据呢???
    nBytesSent = WSASend(pClientContext->GetSocket(), p_wbuf, 1, &dwBytes, dwFlags, p_ol, NULL);
    作者考虑到数据不能一次过发送,要多次发