widnows iocp 的理解

第一步:創建監聽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;
}

發佈了18 篇原創文章 · 獲贊 7 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章