个人IOCP服务器例子解说
這里寫兩方面的解說,一方面,解說iocp內(nèi)部處理情況(這部分以個人查考寫的iocp服務器和客戶端寫的);一方面,參考libeventlibevent-1.4.4-iocp-3 大致調(diào)整給出一個比較標準的服務器和客戶端例子。新手可以通過前部分獲得建立iocp的基本理解;通過后部分建立自己(基于libevent)標準的iocp代碼。
?
一、//先來建立自己的icop吧
?
1)自己的iocp服務器(MyIOCPServer.cpp)
?
#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <iostream>
using namespace std;
// 單句柄數(shù)據(jù)
typedef struct tagPER_HANDLE_DATA
{
?SOCKET Socket;
?SOCKADDR_STORAGE ClientAddr;
?// 將和這個句柄關(guān)聯(lián)的其他有用信息,盡管放在這里面吧
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
// 但I/O 操作數(shù)據(jù)
typedef struct tagPER_IO_DATA
{
?OVERLAPPED Overlapped;
?WSABUF DataBuf;
?char buffer[1024];
?int BufferLen;
?int OperationType; // 可以作為讀寫的標志,為簡單,我忽略了
}PER_IO_DATA, *LPPER_IO_DATA;
//線程函數(shù)
DWORD WINAPI ServerWorkerThread(LPVOID lpParam);
DWORD WINAPI ServerWorkerThread(LPVOID lpParam)
{
?HANDLE CompletionPort = (HANDLE)lpParam;
?DWORD BytesTransferred;
?LPOVERLAPPED lpOverlapped;
?LPPER_HANDLE_DATA PerHandleData = NULL;
?LPPER_IO_DATA PerIoData = NULL;
?DWORD SendBytes;
?DWORD RecvBytes;
?DWORD Flags;
?BOOL bRet = FALSE;
?while (TRUE) //無限循環(huán)
?{
??bRet = GetQueuedCompletionStatus(CompletionPort,&BytesTransferred,(PULONG_PTR)&PerHandleData,(LPOVERLAPPED*)&lpOverlapped,INFINITE);
??// 檢查成功的返回,這兒要注意使用這個宏CONTAINING_RECORD
??PerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(lpOverlapped,PER_IO_DATA,Overlapped);
??// 先檢查一下,看看是否在套接字上已有錯誤發(fā)生
??if (0 == BytesTransferred)
??{
???closesocket(PerHandleData->Socket);
???GlobalFree(PerHandleData);
???GlobalFree(PerIoData);
???continue;
??}
??// 數(shù)據(jù)處理
??char sendBuf[100];
??sprintf(sendBuf,"Welcome %s to? %d %d \n",PerIoData->DataBuf.buf,PerHandleData->Socket,::GetCurrentThreadId());
??send(PerHandleData->Socket,sendBuf,strlen(sendBuf)+1,0);
??//WSASend()
???/*DataBuf.len = DATA_BUFSIZE;?
?? DataBuf.buf = buffer;
??? for(i=0; i < SEND_COUNT ;i++) {
???? WSASend(PerHandleData->Socket, &DataBuf, 1, &SendBytes, 0, &SendOverlapped, NULL); */
??// 成功了!!!這兒就收到了來自客戶端的數(shù)據(jù)
??cout << PerIoData->DataBuf.buf << ::GetCurrentThreadId() << endl;
??Flags = 0;
??// 為下一個重疊調(diào)用建立單I/O 操作數(shù)據(jù)
??ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
??PerIoData->DataBuf.len = 1024;
??PerIoData->DataBuf.buf = PerIoData->buffer;
??PerIoData->OperationType = 0; // read
??WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
?}
?return 0;
}
int main(int argc, _TCHAR* argv[])
{
?//頭部申明
?HANDLE CompletionPort;
?WSADATA wsd;
?SYSTEM_INFO SystemInfo;
?SOCKADDR_IN InternetAddr;
?SOCKET Listen;
?// 加載WinSock2.2
?WSAStartup(MAKEWORD(2, 2), &wsd);
?// 1.創(chuàng)建一個I/O 完成端口
?CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
?// 2.確定系統(tǒng)中有多少個處理器
?GetSystemInfo(&SystemInfo);
?// 3.基于系統(tǒng)中可用的處理器數(shù)量創(chuàng)建工作器線程
?for (int i = 0; i < int(SystemInfo.dwNumberOfProcessors * 2); ++i)
?{
??HANDLE ThreadHandle;
??// 創(chuàng)建一個服務器的工作器線程,并將完成端口傳遞到該線程
??ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,NULL);
??CloseHandle(ThreadHandle);
?}
?// 4.創(chuàng)建一個監(jiān)聽套接字,以下的套路都是固定的。
?Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
?//綁定和監(jiān)聽
?InternetAddr.sin_family = PF_INET;
?InternetAddr.sin_port = htons(6000);
?InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
?bind(Listen, (SOCKADDR*)&InternetAddr, sizeof(InternetAddr));
?listen(Listen, 5);
?//無限循環(huán)
?BOOL b = TRUE;
?while (b)
?{
??PER_HANDLE_DATA * PerHandleData = NULL;
??SOCKADDR_IN saRemote;
??SOCKET Accept;
??int RemoteLen;
??// 5.接收連接,并分配完成端口,這兒可以用AcceptEx 來代替,以創(chuàng)
??// 建可伸縮的Winsock 應用程序。
??RemoteLen = sizeof(saRemote);
??Accept = accept(Listen, (SOCKADDR*)&saRemote, &RemoteLen);
??// 6.創(chuàng)建用來和套接字關(guān)聯(lián)的單句柄數(shù)據(jù)信息結(jié)構(gòu)
??PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
??//cout << "Socket number " << Accept << " connected" << endl;
??PerHandleData->Socket = Accept;
??memcpy(&PerHandleData->ClientAddr, &saRemote, RemoteLen);
??// 7.將接受套接字和完成端口關(guān)聯(lián)起來
??CreateIoCompletionPort((HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,0);
??// 開始在接受套接字上處理I/O
??// 使用重疊I/O 機制,在新建的套接字上投遞一個或多個異步
??// WSARecv 或 WSASend 請求。這些I/O 請求完成后,工作者線程
??// 會為I/O 請求提供服務,之后就可以坐享其成了
??static int const DATA_BUFSIZE = 4096;?
??DWORD RecvBytes = 0;
??DWORD Flags = 0;
??// 單I/O 操作數(shù)據(jù)
??LPPER_IO_DATA PerIoData = NULL;
??PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
??ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
??PerIoData->DataBuf.len = 1024;
??PerIoData->DataBuf.buf = PerIoData->buffer;
??PerIoData->OperationType = 0; // read
??WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
?}
?return 0;
}
?
?
2)自己的iocp客戶端(MyIOCPClient.cpp)
?
#include "stdafx.h"
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
void main()
{
?WORD wVersionRequested;
?WSADATA wsaData;
?int err;
?wVersionRequested = MAKEWORD( 1, 1 );
?err = WSAStartup( wVersionRequested, &wsaData );
?if ( err != 0 ) {
??return;
?}
?if ( LOBYTE( wsaData.wVersion ) != 1 ||
??HIBYTE( wsaData.wVersion ) != 1 ) {
???WSACleanup( );
???return;?
?}
?while (true)
?{
??SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
??SOCKADDR_IN addrSrv;
??addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
??addrSrv.sin_family=AF_INET;
??addrSrv.sin_port=htons(6000);
??connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
??send(sockClient,"This is lisi",strlen("This is lisi")+1,0);
??char recvBuf[100];
??recv(sockClient,recvBuf,100,0);
??printf("%s\n",recvBuf);
??closesocket(sockClient);
?}
?WSACleanup();
}
總結(jié)
以上是生活随笔為你收集整理的个人IOCP服务器例子解说的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IOCP 浅析与实例
- 下一篇: 创建线程后为什么马上调用CloseHan