最近在windows下用udp接收資料,查了下百度,說用完成連接埠比較好用,在學習windows下完成連接埠的的使用,開始以為很複雜,真正搞好了發現還是比較容易使用的,
完成連接埠使用在main函數中先初始化並建立一個線程:
g_hCompletionPort = CreateIoCompletionPort ( INVALID_HANDLE_VALUE, NULL, 0, 0 ) ;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread,
NULL, 0, NULL);
需要定義一個用於接收資料的結構:
typedef struct _PER_HANDLE_DATA
{
SOCKET s;
sockaddr_in addr;
char buf[BUFFER_SIZE];
int nOperationType;
} PER_HANDLE_DATA;
然後分配一個PER_HANDLE_DATA,使用CreateIoCompletionPort將接收的socket控制代碼添加到完成連接埠中:
PER_HANDLE_DATA *pPerHandle =(PER_HANDLE_DATA *)malloc (sizeof(PER_HANDLE_DATA));
pPerHandle->s =socket(AF_INET,SOCK_DGRAM,0);
memset(&pPerHandle->addr,0,sizeof(struct sockaddr_in));
pPerHandle->addr.sin_family=AF_INET;
pPerHandle->addr.sin_port=8888; //udp連接埠號碼
pPerHandle->nOperationType = 1;
bind(pPerHandle->s ,(struct sockaddr *)&pPerHandle->addr,sizeof(struct sockaddr));
CreateIoCompletionPort((HANDLE)pPerHandle->s, g_hCompletionPort, (ULONG_PTR)pPerHandle, 0);
在分配一個OVERLAPPED,使用WSARecv接收資料
OVERLAPPED *pol = (OVERLAPPED *)malloc(sizeof(OVERLAPPED));
WSABUF buf;
buf.buf = pPerHandle->buf;
buf.len = BUFFER_SIZE;
DWORD dwRecv;
DWORD dwFlags = 0;
ret = ::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, pol, NULL);
if (ret <0)
errCode = WSAGetLastError();
while(1)
{
}
線程函數中使用GetQueuedCompletionStatus擷取完成連接埠狀態並處理
void* WorkThread(void* name)
{
DWORD dwTrans;
OVERLAPPED *pOverlapped;
PER_HANDLE_DATA* pPerHandle;
// OVERLAPPEDPLUS *lpPlus;
while (1)
{
BOOL bOK = GetQueuedCompletionStatus(g_hCompletionPort,&dwTrans,(PULONG_PTR)&pPerHandle,&pOverlapped,0);
if(!bOK)
{
Sleep(1);
continue;
}
if (pPerHandle->nOperationType==1) //只處理接收資料,pPerHandle->buf就是接收到資料的內容,dwTrans為接收到的資料長度
{
ProcessRecv(pPerHandle->buf,dwTrans);
WSABUF buf;
buf.buf = pPerHandle->buf ;
buf.len = BUFFER_SIZE;//參數2
pPerHandle->nOperationType = 1;
DWORD nFlags = 0;//參數4
::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, pOverlapped, NULL); //繼續使用WSARecv接收資料
Sleep(1);
}
}
這樣一個簡單的使用完成連接埠實現udp接收資料的程式就寫好了