#include <iostream>
#include <process.h>
#include <winsock2.h> 
#include <windows.h>
//<winsock2.h>与<windows.h>位置调换就会发现重定义/*
#ifndef _WINSOCKAPI_           // 没有包含winsock.h
#define _WINSOCKAPI_           // 避免再包含winsock.h
     #ifndef _WINSOCK2API_      // 没有包含winsock2.h
     #define _WINSOCK2API_      // 避免再包含winsock2.h
         #include <winsock2.h>
         #pragma comment(lib, "ws32_2.lib")
    #endif
#endif
*/
using std::cin;
using std::cout;
using std::endl;const unsigned short PORT=5000;
const unsigned int MSGSIZE=1024;#pragma comment(lib,"ws2_32.lib")typedef enum
{
RECV_POSTED
}
OPERATION_TYPE;typedef struct
{
WSAOVERLAPPED   wsaOverlapped;//放在第一个位置或许有目的的!
DWORD NumberOfBytesRecvd;
WSABUF  wsaBuf;
OPERATION_TYPE OperateType;
DWORD Flag;
char szMessage[MSGSIZE];
}PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA;
//定义一个结构体保存IO数据//unsigned _stdcall WorkerThread(PVOID lParamter);
DWORD WINAPI WorkerThread(PVOID lParamter);
int main()
{
WSADATA wsaData;
int error=WSAStartup(0x0202,&wsaData);
if(error!=0)
{
cout<<"加载套接字库失败!"<<endl;
return -1;
} HANDLE CompletionPort=INVALID_HANDLE_VALUE;
CompletionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
//允许并行执行的线程数量等于主机的CPU数量; SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo); //unsigned int dwThreadId;
DWORD dwThreadId;
for(unsigned int i=0;i<systemInfo.dwNumberOfProcessors;++i)
{
//_beginthreadex(NULL,0,WorkerThread,(void*)CompletionPort,0,&dwThreadId);
CreateThread(NULL, 0, WorkerThread, CompletionPort, 0, &dwThreadId);
} SOCKADDR_IN localAddr;
SOCKET sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//SOCKET sListen=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
localAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
localAddr.sin_family=AF_INET;
localAddr.sin_port=htons(PORT);
bind(sListen,(SOCKADDR*)&localAddr,sizeof(SOCKADDR));
listen(sListen,3); SOCKET sClient; 
SOCKADDR_IN clientAddr;
int len=sizeof(SOCKADDR);
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;
while(true)
{
sClient=accept(sListen,(SOCKADDR*)&clientAddr,&len);
printf("Accepted client %s: %d\n",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port)); CreateIoCompletionPort((HANDLE)sClient,CompletionPort,(ULONG_PTR)sClient,0);
//将这个新来的客户套接字和完全端口绑定在一起。

lpPerIOData=(LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PER_IO_OPERATION_DATA));
//用以获取和调用过程的堆句柄, HEAP_ZERO_MEMORY: 将分配的内存全部清零 lpPerIOData->wsaBuf.len=MSGSIZE;
lpPerIOData->wsaBuf.buf=lpPerIOData->szMessage;
lpPerIOData->OperateType=RECV_POSTED;
WSARecv(sClient,&lpPerIOData->wsaBuf,1,&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flag,&lpPerIOData->wsaOverlapped,NULL);
}
CloseHandle(CompletionPort);
closesocket(sListen);
WSACleanup();
return 0;
}//unsigned _stdcall WorkerThread(PVOID lParamter)
DWORD WINAPI WorkerThread(PVOID lParamter)
{
HANDLE CompletionPort=(HANDLE)lParamter;
DWORD dwBytesTransferred;
    SOCKET sClient=NULL;
    LPPER_IO_OPERATION_DATA lpPerIOData = NULL; while(true)
{
BOOL error=GetQueuedCompletionStatus(CompletionPort,&dwBytesTransferred,
                           (PULONG_PTR&)sClient,(LPOVERLAPPED *)&lpPerIOData,INFINITE);
DWORD dwError=GetLastError();
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |  
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
cout<<"Error Message:"<<lpMsgBuf<<endl;
if(dwBytesTransferred==0xFFFFFFFF)
{
cout<<"dwBytesTransferred==0xFFFFFFFF"<<endl;
return -1;
} if(lpPerIOData->OperateType==RECV_POSTED)
{
if(lpPerIOData->NumberOfBytesRecvd==0)
{
cout<<"Connection was closed by clien!"<<endl;
closesocket(sClient);
HeapFree(GetProcessHeap(),0,lpPerIOData);
}
else
{
lpPerIOData->szMessage[dwBytesTransferred]='\0';
send(sClient,lpPerIOData->szMessage,dwBytesTransferred,0);
//考虑一下这里为什么不用WSASend
}
} memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->wsaBuf.len=MSGSIZE;
lpPerIOData->wsaBuf.buf=lpPerIOData->szMessage;
lpPerIOData->OperateType=RECV_POSTED;
WSARecv(sClient,&lpPerIOData->wsaBuf,1,&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flag,&lpPerIOData->wsaOverlapped,NULL);
} return 0;
}

解决方案 »

  1.   

    关于GetQueuedCompletionStatus函数为什么不是的线程挂起?
    --------------------
    lz这句话,我是在是没读懂
      

  2.   

    这样会所GetQueuedCompletionStatus会使得线程池里面的线程回到  等待线程队列,当有I/O完全队列不为空的时候,I/O端口就会唤醒一个线程到以释放线程队列里面处理 I/O完成的请求;就是追星一个线程处理!当I/O完全队列为空,GetQueuedCompletionStatus不应该执行下去的啊!应该调去暂停线程列表
      

  3.   

    Attempts to dequeue an I/O completion packet from the specified I/O completion port. If there is no completion packet queued, the function waits for a pending I/O operation associated with the completion port to complete.不是线程挂起,应该是等待吧。