第一步:创建监听socket(wsasocket使用重叠结构)
第二步:创建iocp(createiocompleteport),与监听的socket的关联起来(createiocompleteport)【完成键表示这和监听socket的连接信息,可以自己定义结构和这个socket产生联系】
第三步:使用acceptex接受连接(预先取出一个socket来接受新来的客户端socket)【这里需要io数据结构 必须有重叠结构和socket,缓冲区】
第四步:工作线程通过getqueuedcompletestatus获取io的状态和操作【在接受连接完成后需要重新发送连接下一个的请求,投递一个接受请求,等待新的连接到来】
例子如下:(转载)
// by SinCoder Blog : hi.baidu.com/sincoder
/*
#include <WINSOCK2.H>
#include <windows.h>
#include <MSWSOCK.H>
#include <STDIO.H>
#pragma comment(lib,"Mswsock.lib")
#pragma comment(lib,"ws2_32")
#define DATA_LEN 1024
HANDLE hIocp = INVALID_HANDLE_VALUE;
SOCKET m_Listen_Socket = INVALID_SOCKET;
enum
{
IO_READ =0,
IO_WRITE,
IO_ACCEPT,
IO_QUIT,
IO_UNDEFINE
};
class Per_Handle_Data
{
public:
SOCKET s_Socket;
};
class Per_Io_Data
{
public:
OVERLAPPED O_Overlapped;
WSABUF buff;
BYTE Data[DATA_LEN];
int IO_TYPE;
SOCKET New_Socket;
};
DWORD WINAPI WorkerThread(LPVOID lparam)
{
//线程就不开了。。这只是个例子 ,
return 0;
}
void PostIocpRecv(Per_Handle_Data *Iocp_Handle_Data)
{
Per_Io_Data *p_Io_Data=new Per_Io_Data;
p_Io_Data->buff.buf=(char *)p_Io_Data->Data;
p_Io_Data->buff.len=DATA_LEN;
p_Io_Data->IO_TYPE=IO_READ;
ZeroMemory(&p_Io_Data->O_Overlapped,sizeof(OVERLAPPED));
DWORD Bytes;
DWORD Flags=0;
WSARecv(Iocp_Handle_Data->s_Socket,&p_Io_Data->buff,1,&Bytes,&Flags,&p_Io_Data->O_Overlapped,NULL);
}
void PostIocpSend(SOCKET m_Socket,BYTE *data,int datalen)
{
Per_Io_Data *p_Io_Data=new Per_Io_Data;
memcpy(&p_Io_Data->Data,data ,datalen);
p_Io_Data->buff.buf=(char *)p_Io_Data->Data;
p_Io_Data->buff.len=datalen;
p_Io_Data->IO_TYPE=IO_WRITE;
ZeroMemory(&p_Io_Data->O_Overlapped,sizeof(OVERLAPPED));
DWORD Bytes;
DWORD Flags=0;
WSASend(m_Socket,&p_Io_Data->buff,1,&Bytes,Flags,&p_Io_Data->O_Overlapped,NULL);
}
void PostIocpAccept()
{
SOCKET m_New_Socket= WSASocket(AF_INET,SOCK_STREAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);
Per_Handle_Data *p_Handle_Data=new Per_Handle_Data;
p_Handle_Data->s_Socket=m_New_Socket;
Per_Io_Data *p_Io_Data=new Per_Io_Data;
ZeroMemory(&p_Io_Data->O_Overlapped,sizeof(OVERLAPPED));
p_Io_Data->IO_TYPE = IO_ACCEPT;
p_Io_Data->New_Socket=m_New_Socket;
DWORD Bytes_Recv=0;
AcceptEx(m_Listen_Socket,
m_New_Socket,
p_Io_Data->Data,
DATA_LEN-2*(sizeof(sockaddr_in)+16),
sizeof(sockaddr_in)+16,
sizeof(sockaddr_in)+16,
&Bytes_Recv,
&p_Io_Data->O_Overlapped);
}
void PostIocpExit()
{
Per_Handle_Data *p_Handle_Data=new Per_Handle_Data;
p_Handle_Data->s_Socket=m_Listen_Socket;
Per_Io_Data *p_Io_Data=new Per_Io_Data;
ZeroMemory(&p_Io_Data->O_Overlapped,sizeof(OVERLAPPED));
p_Io_Data->IO_TYPE = IO_QUIT;
p_Io_Data->New_Socket=m_Listen_Socket;
p_Io_Data->buff.buf=(char *)p_Io_Data->Data;
p_Io_Data->buff.len=DATA_LEN;
PostQueuedCompletionStatus(hIocp, sizeof(Per_Handle_Data), (ULONG_PTR)p_Handle_Data, (OVERLAPPED*) (&p_Io_Data->O_Overlapped) );
}
int main()
{
#pragma region 初始化
WSAData wsa;
WSAStartup(MAKEWORD(2,2),&wsa);
hIocp=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,0);
m_Listen_Socket=WSASocket(AF_INET,SOCK_STREAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);
sockaddr_in m_addr;
m_addr.sin_family=AF_INET;
m_addr.sin_addr.S_un.S_addr=inet_addr("0.0.0.0"); //在所有的ip上监听,,
m_addr.sin_port=htons(4646);
bind(m_Listen_Socket,(sockaddr *)&m_addr,sizeof(sockaddr));
listen(m_Listen_Socket,SOMAXCONN);
SOCKET m_New_Socket= WSASocket(AF_INET,SOCK_STREAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);
Per_Handle_Data *p_Handle_Data=new Per_Handle_Data;
p_Handle_Data->s_Socket=m_Listen_Socket;
CreateIoCompletionPort((HANDLE)m_Listen_Socket,hIocp,(unsigned long)p_Handle_Data,0);
//XXXX {的确没必要把监听的socket也关联到 iocp 上 因为监听的socket上没有 IO 操作 。。}
//客户端来了 就有了。。。我晕。。
Per_Io_Data *p_Io_Data=new Per_Io_Data;
ZeroMemory(&p_Io_Data->O_Overlapped,sizeof(OVERLAPPED));
p_Io_Data->IO_TYPE = IO_ACCEPT;
p_Io_Data->New_Socket=m_New_Socket;
DWORD Bytes_Recv=0;
AcceptEx(m_Listen_Socket,
m_New_Socket,
p_Io_Data->Data,DATA_LEN-2*(sizeof(sockaddr_in)+16),
sizeof(sockaddr_in)+16,
sizeof(sockaddr_in)+16,
&Bytes_Recv,&p_Io_Data->O_Overlapped);
#pragma endregion
Per_Handle_Data *Lp_Handle_Data;
Per_Io_Data *Lp_Io_Data;
OVERLAPPED *m_Overlapped;
DWORD Bytes=0;
while(TRUE)
{
GetQueuedCompletionStatus(hIocp,&Bytes,(PULONG_PTR)&Lp_Handle_Data,&m_Overlapped,WSA_INFINITE);
Lp_Io_Data = (Per_Io_Data *)CONTAINING_RECORD(m_Overlapped, Per_Io_Data, O_Overlapped);
if (Bytes<=0&&Lp_Io_Data->IO_TYPE!=IO_ACCEPT)
{
printf("Socket: %d exit !\r\n",Lp_Handle_Data->s_Socket);
delete Lp_Handle_Data;
delete Lp_Io_Data;
continue;
}
switch(Lp_Io_Data->IO_TYPE)
{
case IO_ACCEPT:
{
printf("\r\nIO_ACCEPT !\r\n");
Per_Handle_Data *per_Handle_Data=new Per_Handle_Data;
per_Handle_Data->s_Socket=Lp_Io_Data->New_Socket;
CreateIoCompletionPort((HANDLE)Lp_Io_Data->New_Socket,hIocp,(unsigned long)per_Handle_Data,0);
PostIocpAccept();
PostIocpRecv(per_Handle_Data);
}
break;
case IO_READ:
printf("\r\nIO_READ !\r\n");
Lp_Io_Data->Data[Bytes] = '\0';
printf("Socket: %d --> Data: %s\r\n",Lp_Handle_Data->s_Socket,Lp_Io_Data->Data);
PostIocpRecv(Lp_Handle_Data);
PostIocpSend(Lp_Handle_Data->s_Socket,(BYTE*)"123456",6);
delete Lp_Io_Data;
break;
case IO_WRITE:
printf("\r\nIO_WRITE \r\n");
delete Lp_Io_Data;
PostIocpExit();
break;
case IO_QUIT:
printf("Let me quit ! \r\n");
delete Lp_Io_Data;
delete Lp_Handle_Data;
goto END;
case IO_UNDEFINE:
printf("\r\nIO_UNDEFINE \r\n");
delete Lp_Io_Data;
break;
default: break;
}
}
END:
//Do some thing when we exit !!
// .......
closesocket(m_Listen_Socket);
WSACleanup();
return 0;
}