网络编程五种IO模型之重叠IO模型-事件驱动

来源:互联网 发布:java数组动态添加元素 编辑:程序博客网 时间:2024/04/25 05:29
#ifndef Globle_H#define Globle_H#include <iostream>#include <string>#include <algorithm>#include <time.h>using namespace std;#defineBUFFER_SIZE64#definePORT4567char Data[37] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";CRITICAL_SECTION csGeneralData;CRITICAL_SECTION csShowMsg;int Rand(unsigned int n){// RAND_MAX 是rand()能生成的最大值 return rand()%(n==0? RAND_MAX : n);}int ( *pFun)(unsigned int) = &Rand;// 生成一个随机序列void GetData(char *Buf){::EnterCriticalSection(&csGeneralData);random_shuffle(Data, Data+36, pFun);// 郁闷,VC6标准支持不好,只能这样写memcpy(Buf, Data, 20);Buf[20] = '\0';::LeaveCriticalSection(&csGeneralData);}void ShowMsg(const char *pMsg){if(pMsg == NULL) return;EnterCriticalSection(&csShowMsg);cout << pMsg << endl;LeaveCriticalSection(&csShowMsg);}void ShowMsg(const string& sMsg){ShowMsg(sMsg.c_str());}#endif

/*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// 下一步是RECV 操作#define NEXT_IO_SEND1// 下一步是SEND 操作SOCKET Listen;HANDLE ThreadPool[WSA_MAXIMUM_WAIT_EVENTS] = {NULL};CRITICAL_SECTION csOpArray;typedef struct {OVERLAPPED Overlapped[WSA_MAXIMUM_WAIT_EVENTS];WSABUF DataBuf[WSA_MAXIMUM_WAIT_EVENTS];char  Buffer[WSA_MAXIMUM_WAIT_EVENTS][BUFFER_SIZE];BOOL Buffer_Flag[WSA_MAXIMUM_WAIT_EVENTS];// 0 --- Not Use,  1---Used;}OVERLAPPEDDATA, *LPOVERLAPPEDDATA;OVERLAPPEDDATA OpData;typedef struct{DWORD dwIndex;// 标识在OpData中用到的Overlapped[i],DataBuf[i],// Buffer[i], Buffer_Flag[i]BOOL IO_Flag;// 0 --- Read,  1---Send;SOCKET Socket;WSABUF *wsaBuf;// 指向wIndex为索引的OpData中的 &DataBuf[dwIndwx];OVERLAPPED *pOverlapped;// 指向由dwIndex为索引的OpData中的 &Overlapped[dwIndwx]}OVERLAPPEDINFO, *LPOVERLAPPEDINFO;OVERLAPPEDINFO OpInfo[WSA_MAXIMUM_WAIT_EVENTS];DWORD EventTotal = 0;WSAEVENT Event[WSA_MAXIMUM_WAIT_EVENTS]; // 每一个Event[i] 与 每个 OpInfo[i]对应volatile BOOL bExit  = FALSE;static int nThreadCout = 0;void Init(){//InitializeCriticalSection(&csFDRead);InitializeCriticalSection(&csOpArray);InitializeCriticalSection(&csGeneralData);InitializeCriticalSection(&csShowMsg);srand(time(0));ZeroMemory(&OpData, sizeof(OVERLAPPEDDATA));ZeroMemory(&OpInfo, sizeof(OVERLAPPEDINFO));}void BeforeExit(){//DeleteCriticalSection(&csFDRead);DeleteCriticalSection(&csOpArray);DeleteCriticalSection(&csGeneralData);DeleteCriticalSection(&csShowMsg);}BOOL Do_A_Request(DWORD& dwIndex){char Msg[1024] = "";DWORD dwRecv = 0;DWORD dwFlag = 0;OpInfo[dwIndex].IO_Flag = NEXT_IO_SEND;DWORD dwCode = ::WSARecv(OpInfo[dwIndex].Socket, OpInfo[dwIndex].wsaBuf, 1, &dwRecv, &dwFlag,OpInfo[dwIndex].pOverlapped, NULL);if(dwCode == SOCKET_ERROR){dwCode =  ::WSAGetLastError();if(dwCode ==  WSA_IO_PENDING) return TRUE;sprintf(Msg, "do the WSARecv error for socket %d, error code %d",OpInfo[dwIndex].Socket, dwCode);ShowMsg(Msg);return FALSE;}return TRUE;}BOOL AddArray(SOCKET ClientSocket, DWORD& dwIndex){::EnterCriticalSection(&csOpArray);if(EventTotal > WSA_MAXIMUM_WAIT_EVENTS){::LeaveCriticalSection(&csOpArray);return FALSE;}int i = 0;for(; i < WSA_MAXIMUM_WAIT_EVENTS; i++)if(OpData.Buffer_Flag[i] == 0)break;OpData.Buffer_Flag[i]  = 1;WSAEVENT NewEvent = ::WSACreateEvent();Event[EventTotal] = NewEvent;OpData.DataBuf[i].buf = OpData.Buffer[i];OpData.DataBuf[i].len = BUFFER_SIZE;ZeroMemory(&OpData.Overlapped[i], sizeof(WSAOVERLAPPED));OpData.Overlapped[i].hEvent = NewEvent;OpInfo[EventTotal].dwIndex = i;OpInfo[EventTotal].Socket = ClientSocket;OpInfo[EventTotal].wsaBuf = &OpData.DataBuf[i];OpInfo[EventTotal].pOverlapped = &OpData.Overlapped[i];dwIndex = EventTotal;EventTotal++;BOOL bResult = ::Do_A_Request(dwIndex);::LeaveCriticalSection(&csOpArray);return bResult;}void CompressArray(DWORD dwIndex){::EnterCriticalSection(&csOpArray);if(dwIndex < 0 || dwIndex >= WSA_MAXIMUM_WAIT_EVENTS){::LeaveCriticalSection(&csOpArray);return;}OpData.Buffer_Flag[OpInfo[dwIndex].dwIndex] = 0;WSAEVENT hEvent = Event[dwIndex];::WSACloseEvent(hEvent);Event[dwIndex] = Event[EventTotal-1];Event[EventTotal-1] = NULL;OpInfo[dwIndex] = OpInfo[EventTotal-1];ZeroMemory(&OpInfo[EventTotal-1], sizeof(OVERLAPPEDINFO));EventTotal--;::LeaveCriticalSection(&csOpArray);}DWORD WINAPI ConnThread(LPVOID lpParam)  {char Msg[1024] = "";ShowMsg("ConnThread start...");DWORD dwIndex;DWORD dwRecv = 0;DWORD dwFlag = 0;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( !AddArray(Client, dwIndex) ){ShowMsg("Too many connections, can't do the more request!");closesocket(Client);continue;}}ShowMsg("ConnThread exit...");return 0;}DWORD WINAPI WorkerThread(LPVOID lpParam){char Buf[BUFFER_SIZE] = {0};char Msg[1024] = "";ShowMsg("WorkerThread start...");DWORD dwCode;DWORD dwIndex = 0;DWORD dwTransfer = 0;DWORD dwFlag = 0;while(!bExit){if(EventTotal <= 0){Sleep(100);continue;}//dwIndex = ::WSAWaitForMultipleEvents(EventTotal, Event, FALSE, WSA_INFINITE, FALSE);dwIndex = ::WSAWaitForMultipleEvents(EventTotal, Event, FALSE, 500, FALSE);if(dwIndex == WSA_WAIT_TIMEOUT)continue;sprintf(Msg, "Total clients:%d", EventTotal);ShowMsg(Msg);dwIndex -= WSA_WAIT_EVENT_0;WSAResetEvent(Event[dwIndex]);BOOL bResult = ::WSAGetOverlappedResult(OpInfo[dwIndex].Socket, OpInfo[dwIndex].pOverlapped, &dwTransfer, FALSE, &dwFlag);if(!bResult){dwCode = ::WSAGetLastError();if(dwCode == WSA_IO_PENDING)continue;sprintf(Msg, "Call WSAGetOverlappedResult for Socket %d occurs an error %d\nClose the connection", OpInfo[dwIndex].Socket, dwCode);ShowMsg(Msg);closesocket(OpInfo[dwIndex].Socket);::CompressArray(dwIndex);}else{if(dwTransfer == 0){sprintf(Msg, "The connection for Socket %d is closed", OpInfo[dwIndex].Socket);ShowMsg(Msg);closesocket(OpInfo[dwIndex].Socket);::CompressArray(dwIndex);continue;}if(OpInfo[dwIndex].IO_Flag == NEXT_IO_SEND){CopyMemory(Buf, OpInfo[dwIndex].wsaBuf->buf, dwTransfer);Buf[dwTransfer] = '\0';sprintf(Msg, "Received data from socket %d: %s", OpInfo[dwIndex].Socket, Buf);ShowMsg(Msg);OpInfo[dwIndex].IO_Flag = NEXT_IO_READ;GetData(OpInfo[dwIndex].wsaBuf->buf);DWORD dwSend = 0;// 最好别注释下面3句代码//WSAEVENT hEvent = OpInfo[dwIndex].pOverlapped->hEvent;//ZeroMemory(OpInfo[dwIndex].pOverlapped, sizeof(OVERLAPPED));//OpInfo[dwIndex].pOverlapped->hEvent = hEvent;dwCode = ::WSASend(OpInfo[dwIndex].Socket, OpInfo[dwIndex].wsaBuf, 1, &dwSend, dwFlag,OpInfo[dwIndex].pOverlapped, NULL);if(dwCode == SOCKET_ERROR && ::WSAGetLastError() != WSA_IO_PENDING){dwCode = ::WSAGetLastError();sprintf(Msg, "Do the WSARecv error for socket %d, error code %d",OpInfo[dwIndex].Socket, dwCode);ShowMsg(Msg);//if(dwCode == WSA_IO_PENDING || dwCode == WSAECONNRESET)//continue;closesocket(OpInfo[dwIndex].Socket);::CompressArray(dwIndex);}}else// NEXT_IO_READ{sprintf(Msg, "Sended data to socket %d: %s", OpInfo[dwIndex].Socket, OpInfo[dwIndex].wsaBuf->buf);ShowMsg(Msg);OpInfo[dwIndex].IO_Flag = NEXT_IO_SEND;DWORD dwRecv = 0;ZeroMemory(OpInfo[dwIndex].wsaBuf->buf, OpInfo[dwIndex].wsaBuf->len);// 最好别注释下面3句代码//WSAEVENT hEvent = OpInfo[dwIndex].pOverlapped->hEvent;//ZeroMemory(OpInfo[dwIndex].pOverlapped, sizeof(OVERLAPPED));//OpInfo[dwIndex].pOverlapped->hEvent = hEvent;dwCode = ::WSARecv(OpInfo[dwIndex].Socket, OpInfo[dwIndex].wsaBuf, 1, &dwRecv, &dwFlag,OpInfo[dwIndex].pOverlapped, NULL);if(dwCode == SOCKET_ERROR && ::WSAGetLastError() != WSA_IO_PENDING){dwCode = ::WSAGetLastError();sprintf(Msg, "Do the WSARecv error for socket %d, error code %d",OpInfo[dwIndex].Socket, dwCode);ShowMsg(Msg);//if(dwCode == WSA_IO_PENDING || dwCode == WSAECONNRESET)//continue;closesocket(OpInfo[dwIndex].Socket);::CompressArray(dwIndex);}}}}ShowMsg("WorkerThread exit...");return 0;}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);// the smameif(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;//hThread = ::CreateThread(NULL, NULL, SendThread, 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]);for(i = 0; i < EventTotal; i++)closesocket(OpInfo[i].Socket);for(i = 1; i < EventTotal; i++)::WSACloseEvent(Event[i]);::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;}