TAG:
完成端口是基于Windows 重叠IO 的 一种IO 管理模型,提供了最高的效率. 下面是练习使用的一个例子.服务器为别人所写.我只是消化了一下.为了配合测试,写了一个小小的客户端. 都放在这里,加深自己的记忆吧. 服务器代码: // IOCP.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #define _WIN32_WINNT 0x0500 #include <cstdlib> #include <clocale> #include <ctime> #include <iostream> #include <vector> #include <algorithm> #include <WinSock2.h> #include <mswsock.h> using namespace std; #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "mswsock.lib") const int MAX_BUFFER_SIZE = 1024; const int PRE_SEND_SIZE = 1024; const int QUIT_TIME_OUT = 3000; //退出时主线程分80次Sleep完3000MS, 以等待workThread退出 const int PRE_DOT_TIMER = QUIT_TIME_OUT / 80; typedef enum{IoTransFile, IoSend, IoRecv, IoQuit} IO_TYPE; typedef struct { SOCKET hSocket; SOCKADDR_IN ClientAddr; } PRE_SOCKET_DATA, *PPRE_SOCKET_DATA; typedef struct { OVERLAPPED oa; WSABUF DataBuf; char Buffer[MAX_BUFFER_SIZE]; IO_TYPE IoType; } PRE_IO_DATA, *PPRE_IO_DATA; typedef vector<PPRE_SOCKET_DATA> SocketDataVector; typedef vector<PPRE_IO_DATA> IoDataVector; SocketDataVector gSockDataVec; IoDataVector gIoDataVec; CRITICAL_SECTION csProtection; char *TimeNow(void) { time_t t = time(NULL); tm *localtm = localtime(&t); static char timemsg[512]={0}; strftime(timemsg, 512, "%Z: %B %d %X %Y", localtm); return timemsg; } BOOL TransFile(PPRE_IO_DATA pIoData, PPRE_SOCKET_DATA pSocketData, DWORD dwNameLen) { pIoData->Buffer[dwNameLen-1] = ''\\0''; HANDLE hFile = CreateFile(pIoData->Buffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); BOOL bRet = FALSE; if (hFile != INVALID_HANDLE_VALUE) { cout<<"Transmit File"<<pIoData->Buffer<<"to client"<<endl; pIoData->IoType = IoTransFile; memset(&pIoData->oa, 0, sizeof(OVERLAPPED)); *reinterpret_cast<HANDLE*>(pIoData->Buffer) = hFile; // 此处保存句柄是为了在传输完毕后关闭文件 TransmitFile(pSocketData->hSocket, hFile, GetFileSize(hFile, NULL), PRE_SEND_SIZE, reinterpret_cast<LPOVERLAPPED>(pIoData), NULL, TF_USE_SYSTEM_THREAD); bRet =(WSAGetLastError() == WSA_IO_PENDING); } else cout<<"Transmit File"<<"Error:"<<GetLastError()<<endl; return bRet; } DWORD WINAPI ThreadProc(LPVOID IocpHandle) { DWORD dwRecv = 0; DWORD dwFlags = 0; HANDLE hIocp = reinterpret_cast<HANDLE> (IocpHandle); DWORD dwTransCount = 0; PPRE_IO_DATA pPreIoData = NULL; PPRE_SOCKET_DATA pPreHandleData = NULL; while (TRUE) { if (GetQueuedCompletionStatus(hIocp, &dwTransCount, reinterpret_cast<LPDWORD>(&pPreHandleData), reinterpret_cast<LPOVERLAPPED*>(&pPreIoData), INFINITE)) { if (0 == dwTransCount && IoQuit != pPreIoData->IoType) { cout<<"Client"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<" is closed"<<endl; closesocket(pPreHandleData->hSocket); EnterCriticalSection(&csProtection); IoDataVector::iterator itIoDelete = find(gIoDataVec.begin(), gIoDataVec.end(), pPreIoData); gIoDataVec.erase(itIoDelete); // 这个地方用vector不合理,删除成本太高,不如改用list SocketDataVector::iterator itSockDel = find(gSockDataVec.begin(), gSockDataVec.end(), pPreHandleData); gSockDataVec.erase(itSockDel); LeaveCriticalSection(&csProtection); delete *itIoDelete; delete *itSockDel; continue; } switch(pPreIoData->IoType) { case IoTransFile: // 传送文件完成 cout<<"Client"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<"Transmit finished"<<endl; CloseHandle(reinterpret_cast<HANDLE*>(pPreIoData->Buffer)); goto LRERECV; case IoSend: cout<<"Client"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<"send finished"<<endl; // 处理结束后,重新发起WSARecv请求: LRERECV: pPreIoData->IoType = IoRecv; pPreIoData->DataBuf.len = MAX_BUFFER_SIZE; memset(&pPreIoData->oa, 0, sizeof(OVERLAPPED)); WSARecv(pPreHandleData->hSocket, &pPreIoData->DataBuf, 1, &dwRecv, &dwFlags, reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData), NULL); break; case IoRecv: cout<<"Client:"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<"recv finished"<<endl; pPreIoData->IoType = IoSend; if (!TransFile(pPreIoData, pPreHandleData, dwTransCount)) { memset(&pPreIoData->oa,0, sizeof(OVERLAPPED)); strcpy(pPreIoData->DataBuf.buf, "File transmit error!\\r\\n"); pPreIoData->DataBuf.len = strlen(pPreIoData->DataBuf.buf); WSASend(pPreHandleData->hSocket, &pPreIoData->DataBuf, 1, &dwRecv, dwFlags, reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData), NULL); } break; case IoQuit: goto LQUIT; default: ; } } } LQUIT: return 0; } HANDLE hIocp = NULL; SOCKET hListen = NULL; BOOL WINAPI ShutdownHandler(DWORD dwCtrlType) { PRE_SOCKET_DATA PreSockData = {0}; PRE_IO_DATA PreIoData = {0}; PreIoData.IoType = IoQuit; if (hIocp) { PostQueuedCompletionStatus(hIocp, 1, reinterpret_cast<ULONG_PTR>(&PreSockData), reinterpret_cast<LPOVERLAPPED>(&PreIoData)); cout<<"Shutdown at"<<TimeNow()<<endl<<"Wait for a moment please"<<endl; for (int t = 0; t < 80; t++) { Sleep(PRE_DOT_TIMER); cout<<"."; } CloseHandle(hIocp); } int i = 0; for (; i < gSockDataVec.size(); i++) { PPRE_SOCKET_DATA pSockData = gSockDataVec[i]; closesocket(pSockData->hSocket); delete pSockData; } for (i= 0; i <gIoDataVec.size(); i++) { PPRE_IO_DATA pIoData = gIoDataVec[i]; delete pIoData; } DeleteCriticalSection(&csProtection); if (hListen) closesocket(hListen); WSACleanup(); exit(0); return TRUE; } LONG WINAPI MyExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) { ShutdownHandler(0); return EXCEPTION_EXECUTE_HANDLER; } USHORT DefPort = 8182; int main(int argc, char* argv[]) { if (argc == 2) DefPort = atoi(argv[1]); InitializeCriticalSection(&csProtection); SetUnhandledExceptionFilter(MyExceptionFilter); SetConsoleCtrlHandler(ShutdownHandler, TRUE); // process CTRL+C hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); WSADATA data = {0}; WSAStartup(0x0202, &data); hListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == hListen) { ShutdownHandler(0); } SOCKADDR_IN addr = {0}; addr.sin_family = AF_INET; addr.sin_port = htons(DefPort); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(hListen, reinterpret_cast<PSOCKADDR>(&addr), sizeof(addr)) == SOCKET_ERROR) { ShutdownHandler(0); } if (listen(hListen, 256) == SOCKET_ERROR) ShutdownHandler(0); SYSTEM_INFO si = {0}; GetSystemInfo(&si); si.dwNumberOfProcessors<<= 1; for (int i= 0; i < si.dwNumberOfProcessors; i++) { // CreateThread(NULL, NULL, ThreadProc, hIocp, NULL, NULL); QueueUserWorkItem(ThreadProc, hIocp, WT_EXECUTELONGFUNCTION); } cout<<"Startup at"<<TimeNow()<<endl<<"Work on Port"<<DefPort<<endl <<"Press CTRL+C to Shutdown"<<endl<<endl<<endl; while(TRUE) { int namelen = sizeof(addr); memset(&addr,0, sizeof(addr)); SOCKET hAccept = accept(hListen, reinterpret_cast<PSOCKADDR>(&addr), &namelen); if (hAccept != INVALID_SOCKET) { cout<<"accept a client:"<<inet_ntoa(addr.sin_addr)<<":"<<ntohs(addr.sin_port)<<endl; PPRE_SOCKET_DATA pPreHandleData = new PRE_SOCKET_DATA; pPreHandleData->hSocket = hAccept; memcpy(&pPreHandleData->ClientAddr, &addr, sizeof(addr)); CreateIoCompletionPort(reinterpret_cast<HANDLE>(hAccept), hIocp, reinterpret_cast<DWORD> (pPreHandleData), 0); PPRE_IO_DATA pPreIoData = new (nothrow) PRE_IO_DATA; i[FS:PAGE]f (pPreIoData) { EnterCriticalSection(&csProtection); gSockDataVec.push_back(pPreHandleData); gIoDataVec.push_back(pPreIoData); LeaveCriticalSection(&csProtection); memset(pPreIoData, 0, sizeof(PRE_IO_DATA)); pPreIoData->IoType = IoRecv; pPreIoData->DataBuf.len = MAX_BUFFER_SIZE; pPreIoData->DataBuf.buf = pPreIoData->Buffer; DWORD dwRecv = 0; DWORD dwFlags = 0; WSARecv(hAccept, &pPreIoData->DataBuf, 1, &dwRecv, &dwFlags, reinterpret_cast<WSAOVERLAPPED*> (pPreIoData), NULL); } else { delete pPreHandleData; closesocket(hAccept); } } } return 0; } 客户端: #include <WinSock.h> #include <iostream> using namespace std; #pragma comment(lib, "ws2_32.lib") int main(int argc, char* argv[]) { WSADATA wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { cout<<"WSAStartup error, exit\\n"; return -1; } SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(8182); addr.sin_addr.s_addr = inet_addr("192.168.4.121"); int ierr = connect(sock, (sockaddr*)&addr, sizeof(addr)); if (ierr != 0) return -1; char szBuff[2000] = {0}; char *s = "c:\\\\1.txt"; ierr = send(sock, s, strlen(s)+1, 0); if (ierr != (strlen(s)+1)) return -1; int iLen = recv(sock, szBuff, 1024, 0); if (iLen > 0) { for (int i = 0; i < iLen; i++) cout<<szBuff[i]; } else cout<<"recv() error"<<endl; return 0; } (iwgh) |