网络编程五种IO模型之重叠IO模型-完成例程

来源:互联网 发布:java数组动态添加元素 编辑:程序博客网 时间:2024/03/29 17:21
/*client.cpp  */#include <Winsock2.h>#include <stdio.h>#include <conio.h>#include <iostream>#include "Globle.h"#pragma comment(lib, "ws2_32.lib")#defineMAX_THREAD5HANDLE ThreadPool[MAX_THREAD] = {NULL};volatile BOOL bExit = FALSE;void Init(){InitializeCriticalSection(&csGeneralData);InitializeCriticalSection(&csShowMsg);srand(time(0));}void BeforeExit(){DeleteCriticalSection(&csGeneralData);DeleteCriticalSection(&csShowMsg);}DWORD GetSocket(SOCKET &s){DWORD dwCode;char Msg[1024] = "";closesocket(s);s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //建立一个TCP/IP协议的套接字if(s == INVALID_SOCKET){dwCode = WSAGetLastError();sprintf(Msg, "\nCan't create the socket:%d \n", dwCode);ShowMsg(Msg);return dwCode;}return 0;}DWORD DoConnect(SOCKET &s){DWORD dwCode;//char Msg[1024] = "";SOCKADDR_IN server;server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = inet_addr("127.0.0.1");dwCode = connect(s, (sockaddr*)&server, sizeof(server));return dwCode;}// 处理连接DWORD WINAPI WorkerThread(LPVOID lpParam){char Msg[1024] = "";int iIndex = (int)lpParam;string sThreadName;sprintf(Msg, "WorkerThread %d ", iIndex);sThreadName = Msg;sprintf(Msg, "WorkerThread %d start...\n", iIndex);ShowMsg(Msg);char Buf[BUFFER_SIZE] = "";BOOL bConnect = FALSE;SOCKET s;DWORD dwCode;GetSocket(s);while(!bExit){if(!bConnect){while( (dwCode=DoConnect(s)) != 0 && !bExit){dwCode = WSAGetLastError();sprintf(Msg, "can't connect to the server:%d \n", dwCode);::ShowMsg(sThreadName+Msg);if(dwCode != WSAECONNREFUSED && dwCode !=WSAENETUNREACH && dwCode != WSAETIMEDOUT){GetSocket(s);sprintf(Msg, "create socket %d", s);ShowMsg(sThreadName + Msg);}Sleep(3000);ShowMsg(sThreadName + "connect to the server...");}if(dwCode == 0)bConnect = TRUE;if(bExit)break;}Sleep(2000);// 延时2秒::GetData(Buf);dwCode = ::send(s, Buf, 20, 0);sprintf(Msg, "socket %d sended data to the server:%s", s, Buf);ShowMsg(sThreadName + Msg);if(dwCode == SOCKET_ERROR){dwCode = ::WSAGetLastError();sprintf(Msg, "socket %d can't send data to the server:%d \n", s, dwCode);::ShowMsg(sThreadName + Msg);//if(dwCode == WSAESHUTDOWN || dwCode == WSAECONNABORTED || dwCode == WSAECONNRESET//|| dwCode == WSAENOTSOCK){GetSocket(s);bConnect = FALSE;continue;}}dwCode = ::recv(s, Buf, BUFFER_SIZE, 0);if(dwCode == SOCKET_ERROR){dwCode = ::WSAGetLastError();sprintf(Msg, "socket %d can't receive data from the server:%d \n", s, dwCode);::ShowMsg(sThreadName+Msg);//if(dwCode == WSAESHUTDOWN || dwCode == WSAECONNABORTED || dwCode == WSAECONNRESET//|| dwCode == WSAENOTSOCK){GetSocket(s);bConnect = FALSE;continue;}}sprintf(Msg, "socket %d received data from the server:%s", s, Buf);ShowMsg(sThreadName+Msg);Sleep(500);}closesocket(s);sprintf(Msg, "WorkerThread %d exit...\n", iIndex);ShowMsg(Msg);return 0;}void main(){int i;Init();WSADATA wsaData;DWORD dwCode = WSAStartup(MAKEWORD(2, 2), &wsaData);//初始化WinSockif(dwCode != 0){printf("\nCan't find find a usable WinSock DLL");goto EXIT;}if ( LOBYTE( wsaData.wVersion ) != 2 ||  HIBYTE( wsaData.wVersion ) != 2 ){printf("\nCan't find the socket version required.");goto EXIT;    }for(i = 0; i < MAX_THREAD; i++){HANDLE hThread = ::CreateThread(NULL, NULL, WorkerThread, (LPVOID)i, 0, NULL);ThreadPool[i] = hThread;}ShowMsg("Press 'q' to exit...\n");while(_getch() != 'q' && _getch() != 'Q'){ShowMsg("Press 'q' to exit...\n");}bExit = TRUE;::WaitForMultipleObjects(MAX_THREAD, ThreadPool, TRUE, INFINITE);for(i = 0; i < MAX_THREAD; i++)::CloseHandle(ThreadPool[i]);EXIT:::WSACleanup();BeforeExit();printf("press any key to exit...");getch();    return;}

#include <conio.h>#include <stdio.h>#include <winsock2.h>//#include <mswsock.h>#include "Globle.h"#pragma comment(lib, "ws2_32.lib")//#defineMAX_CLIENT5#define NEXT_IO_READ0#define NEXT_IO_SEND1SOCKET Listen;HANDLE ThreadPool[WSA_MAXIMUM_WAIT_EVENTS] = {NULL};CRITICAL_SECTION csAccept;volatile DWORD EventTotal = 0;volatile DWORD TotalClients = 0;// volatile DWORD dwLeftConnect = 0;SOCKET Client[WSA_MAXIMUM_WAIT_EVENTS];// 临时存放连接的客户端队列, 取出以后dwLeftConnect减一WSAEVENT Event[WSA_MAXIMUM_WAIT_EVENTS];volatile BOOL bExit  = FALSE;static int nThreadCout = 0;typedef struct// 第一个成员必须是OverLapped结构{OVERLAPPED Overlapped;WSABUF DataBuf;CHAR Buffer[BUFFER_SIZE];DWORD dwOpType;SOCKET Socket;} PER_IO_OP_DATA, * LPPER_IO_OP_DATA;void CALLBACK WorkerRoutine(DWORD dwError,  DWORD cbTransferred,  LPWSAOVERLAPPED lpOverlapped,  DWORD dwFlags);void Init(){//InitializeCriticalSection(&csFDRead);InitializeCriticalSection(&csAccept);InitializeCriticalSection(&csGeneralData);InitializeCriticalSection(&csShowMsg);srand(time(0));}void BeforeExit(){//DeleteCriticalSection(&csFDRead);DeleteCriticalSection(&csAccept);DeleteCriticalSection(&csGeneralData);DeleteCriticalSection(&csShowMsg);}BOOL Add_Client(SOCKET& ClientSocket){BOOL bResult = TRUE;EnterCriticalSection(&csAccept);if(dwLeftConnect >= WSA_MAXIMUM_WAIT_EVENTS)bResult = FALSE;elseClient[dwLeftConnect++] = ClientSocket;LeaveCriticalSection(&csAccept);return bResult;}void Get_Client(SOCKET& ClientSocket){EnterCriticalSection(&csAccept);if(dwLeftConnect > 0){ClientSocket = Client[dwLeftConnect-1];Client[dwLeftConnect--] = 0;}elseClientSocket = INVALID_SOCKET;LeaveCriticalSection(&csAccept);}DWORD WINAPI ConnThread(LPVOID lpParam)  {char Msg[1024] = "";ShowMsg("ConnThread start...");//DWORD dwCode;Event[EventTotal++] = ::WSACreateEvent();while(!bExit){SOCKET Client = accept(Listen, NULL, NULL);if(Client == SOCKET_ERROR){sprintf(Msg, "Accept error %d", ::WSAGetLastError());ShowMsg(Msg);continue;}sprintf(Msg, "Socket %d connected...", Client);ShowMsg(Msg);if(!Add_Client(Client)){closesocket(Client);sprintf(Msg, "The Client queue is full, can't do the request for the socket %d, close the connection.",Client);ShowMsg(Msg);continue;}::InterlockedIncrement((LPLONG)&TotalClients);}ShowMsg("ConnThread exit...");return 0;}DWORD WINAPI WorkerThread(LPVOID lpParam){char Msg[1024] = "";ShowMsg("WorkerThread start...");DWORD dwCode;DWORD dwIndex;SOCKET Client;DWORD dwRecv = 0;DWORD dwFlag = 0;while(!bExit){Get_Client(Client);if(Client != INVALID_SOCKET){LPPER_IO_OP_DATA lpPerIoData = (LPPER_IO_OP_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OP_DATA));if (NULL == lpPerIoData){sprintf(Msg, "GlobalAlloc() failed with error %d\n", GetLastError());ShowMsg(Msg);closesocket(Client);continue;}// 下一次操作置为发送操作lpPerIoData->dwOpType = NEXT_IO_SEND;lpPerIoData->DataBuf.buf = lpPerIoData->Buffer;lpPerIoData->DataBuf.len = BUFFER_SIZE;lpPerIoData->Socket = Client;dwFlag = 0;//  accept接到了数据,就放到PerIoData中,而perIoData又通过线程中的函数取出dwCode = WSARecv(Client, &lpPerIoData->DataBuf, 1, &dwRecv, &dwFlag,&(lpPerIoData->Overlapped), WorkerRoutine);if (dwCode == SOCKET_ERROR){dwCode = WSAGetLastError();if (dwCode == WSA_IO_PENDING) continue;// WSA_IO_PENDING == ERROR_IO_PENDINGsprintf(Msg, "WSARecv() failed with error %d\n", dwCode);ShowMsg(Msg);closesocket(Client);::GlobalFree(lpPerIoData);::InterlockedDecrement((LPLONG)&TotalClients);continue;}}//// 需要线程处于可激活状态, 可调用 WSAWaitForMultipleEvents 或 SleepEx()////#define USE_SLEEPEX#ifndef USE_SLEEPEX// 1、调用 WSAWaitForMultipleEvents//dwIndex = ::WSAWaitForMultipleEvents(EventTotal, Event, FALSE, WSA_INFINITE, FALSE);dwIndex = ::WSAWaitForMultipleEvents(EventTotal, Event, FALSE, 1000, TRUE);if(dwIndex == WAIT_IO_COMPLETION){ShowMsg("WSAWaitForMultipleEvents : WAIT_IO_COMPLETION");continue;}else{if(dwIndex == WSA_WAIT_TIMEOUT)continue;dwIndex -= WSA_WAIT_EVENT_0;WSAResetEvent(Event[dwIndex]);}#else// 2. 或者调用 SleepExdwIndex = SleepEx(500, TRUE);if(dwIndex == WAIT_IO_COMPLETION){ShowMsg("SleepEx : WAIT_IO_COMPLETION");continue;}#endif}ShowMsg("WorkerThread exit...");return 0;} void CALLBACK WorkerRoutine(DWORD dwError,  DWORD cbTransferred,  LPWSAOVERLAPPED lpOverlapped,  DWORD dwFlags){DWORD dwSend, dwRecv;DWORD dwOpFlags = 0;DWORD dwCode;LPPER_IO_OP_DATA lpPerIoData = (LPPER_IO_OP_DATA)lpOverlapped;char Msg[1024] = "";sprintf(Msg, "Total clients:%d", TotalClients);ShowMsg(Msg);if(dwError != 0 || cbTransferred == 0){if(dwError != 0)sprintf(Msg, "Socket %d occured en error %d", lpPerIoData->Socket, dwError);elsesprintf(Msg, "The connection for Socket %d is closed", lpPerIoData->Socket);ShowMsg(Msg);closesocket(lpPerIoData->Socket);::GlobalFree(lpPerIoData);::InterlockedDecrement((LPLONG)&TotalClients);return;}if(lpPerIoData->dwOpType == NEXT_IO_SEND){sprintf(Msg, "Received data from socket %d: %s", lpPerIoData->Socket, lpPerIoData->DataBuf.buf);ShowMsg(Msg);GetData(lpPerIoData->DataBuf.buf);ZeroMemory(&lpPerIoData->Overlapped, sizeof(OVERLAPPED));lpPerIoData->dwOpType = NEXT_IO_READ;dwCode = ::WSASend(lpPerIoData->Socket, &lpPerIoData->DataBuf, 1, &dwSend, dwOpFlags,&lpPerIoData->Overlapped, WorkerRoutine);if(dwCode == SOCKET_ERROR && ::WSAGetLastError() != WSA_IO_PENDING){dwCode = ::WSAGetLastError();sprintf(Msg, "Do the WSARecv error for socket %d, error code %d",lpPerIoData->Socket, dwCode);ShowMsg(Msg);closesocket(lpPerIoData->Socket);::GlobalFree(lpPerIoData);::InterlockedDecrement((LPLONG)&TotalClients);}}else // NEXT_IO_READ{sprintf(Msg, "Sended data to socket %d: %s", lpPerIoData->Socket, lpPerIoData->Buffer);ShowMsg(Msg);ZeroMemory(&lpPerIoData->Overlapped, sizeof(OVERLAPPED));lpPerIoData->dwOpType = NEXT_IO_SEND;dwRecv = 0;dwCode = ::WSARecv(lpPerIoData->Socket, &lpPerIoData->DataBuf, 1, &dwRecv, &dwOpFlags,&lpPerIoData->Overlapped, WorkerRoutine);if(dwCode == SOCKET_ERROR && ::WSAGetLastError() != WSA_IO_PENDING){dwCode = ::WSAGetLastError();sprintf(Msg, "Do the WSARecv error for socket %d, error code %d",lpPerIoData->Socket, dwCode);ShowMsg(Msg);closesocket(lpPerIoData->Socket);::GlobalFree(lpPerIoData);::InterlockedDecrement((LPLONG)&TotalClients);}}}int main(){int i = 0;DWORD dwCode;WSADATA wsaData;HANDLE hThread = NULL;Init();dwCode = WSAStartup(MAKEWORD(2,2), &wsaData);if(dwCode != 0){printf("\nCan't find find a usable WinSock DLL");goto EXIT;}if ( LOBYTE( wsaData.wVersion ) != 2 ||  HIBYTE( wsaData.wVersion ) != 2 ){printf("\nCan't find the socket version required.");goto EXIT;    }Listen = ::WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);//Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(Listen == INVALID_SOCKET){cout << "\nCan't create the socket:" << WSAGetLastError() << endl;goto EXIT;}SOCKADDR_IN sockAddr;sockAddr.sin_family = AF_INET;sockAddr.sin_addr.s_addr = ADDR_ANY;sockAddr.sin_port = htons(PORT);dwCode = bind(Listen, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));if(dwCode == SOCKET_ERROR){::closesocket(Listen);cout << "\nCan't bind the socket:" << WSAGetLastError() << endl;goto EXIT;}dwCode = listen(Listen, 20);if(dwCode == SOCKET_ERROR){::closesocket(Listen);cout << "\nCan't listen:" << WSAGetLastError() << endl;goto EXIT;}hThread = ::CreateThread(NULL, NULL, ConnThread, NULL, 0, NULL);// CREATE_SUSPENDEDThreadPool[nThreadCout++] = hThread;hThread = ::CreateThread(NULL, NULL, WorkerThread, 0, 0, NULL);ThreadPool[nThreadCout++] = hThread;ShowMsg("Press 'q' to exit...\n");while(_getch() != 'q' && _getch() != 'Q'){ShowMsg("Press 'q' to exit...\n");}bExit = TRUE;::WSASetEvent(Event[0]);::closesocket(Listen);::WaitForMultipleObjects(nThreadCout, ThreadPool, TRUE, INFINITE);for(i = 0; i < nThreadCout; i++)::CloseHandle(ThreadPool[i]);EXIT:WSACleanup();BeforeExit();printf("\nPress any key to exit...");_getch();return 0;}

原创粉丝点击