本文主要是介绍WSA重叠IO,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
服务端:
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <Windows.h>#define PORT 6000
#define IP_ADDRESS "127.0.0.1"
#define MSGSIZE 1024class PerSocketData
{
public:WSAOVERLAPPED overlap;WSABUF buffer;char szMessage[MSGSIZE];DWORD NumberOfBytesRecvd;DWORD flags;
};class SocketListWithIOEvent
{
public:SOCKET socketArray[MAXIMUM_WAIT_OBJECTS];PerSocketData* overLappedData[MAXIMUM_WAIT_OBJECTS];WSAEVENT eventArray[MAXIMUM_WAIT_OBJECTS];int totalConn;
public:SocketListWithIOEvent(){totalConn = 0;for (size_t i = 0; i < MAXIMUM_WAIT_OBJECTS; i++){socketArray[i] = 0;overLappedData[i] = NULL;eventArray[i] = NULL;}}PerSocketData* insetSocket(SOCKET s){socketArray[totalConn] = s;overLappedData[totalConn] = (PerSocketData*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PerSocketData));overLappedData[totalConn]->buffer.len = MSGSIZE;overLappedData[totalConn]->buffer.buf = overLappedData[totalConn]->szMessage;overLappedData[totalConn]->overlap.hEvent = WSACreateEvent();eventArray[totalConn] = overLappedData[totalConn]->overlap.hEvent;return overLappedData[totalConn++];}void deleteSocket(int index){closesocket(socketArray[index]);WSACloseEvent(eventArray[index]);HeapFree(GetProcessHeap(), 0, overLappedData[index]);if (index < totalConn - 1){socketArray[index] = socketArray[totalConn - 1];overLappedData[index] = overLappedData[totalConn - 1];eventArray[index] = eventArray[totalConn - 1];}overLappedData[--totalConn] = NULL;}
};//当main的while里面插入的sock,有事件发生时,就不进行continue并往下执行.
//假如一个新的客户端连接并发送了数据:123,main函数里面的while循环里面插入了这个新的客户端,并调用WSArecv接受数据:123.
//所以workThread线程,有事件发生了(接受道数据:123),然后手动复位,通过WSAGetOverlappedResult获取收到的数据,并将数据原封不动的发给客户端.
//然后又调用非阻塞性的WSArecv接受数据,如果调用WSArecv瞬间有数据,那么就又重复以上步骤,如果调用WSArecv瞬间数据还没收到,则WSArecv不管直接返回(会在后台挂起,等待数据到达,有点类似于自己开了个线程,一直等待执行,有数据返回并关闭线程),WSAWaitForMultipleEvents就没有事件发生,就又进行continue,循环等待事件发生.
DWORD WINAPI workThread(LPVOID lpParam)
{int nRes;int nCurrentIndex;DWORD cbTransFerred;SocketListWithIOEvent* sockList = (SocketListWithIOEvent*)lpParam;while (true){nRes = WSAWaitForMultipleEvents(sockList->totalConn, sockList->eventArray, FALSE, 1000, FALSE);if (nRes == WSA_WAIT_FAILED || nRes == WSA_WAIT_TIMEOUT){continue;}nCurrentIndex = nRes - WSA_WAIT_EVENT_0;WSAResetEvent(sockList->eventArray[nCurrentIndex]);WSAGetOverlappedResult(sockList->socketArray[nCurrentIndex],&sockList->overLappedData[nCurrentIndex]->overlap,&cbTransFerred,TRUE,&sockList->overLappedData[sockList->totalConn]->flags);if (cbTransFerred == 0){printf("Client 断开链接!\r\n");sockList->deleteSocket(nCurrentIndex);}else{std::cout << sockList->overLappedData[nCurrentIndex]->szMessage << std::endl;send(sockList->socketArray[nCurrentIndex], sockList->overLappedData[nCurrentIndex]->szMessage, cbTransFerred, 0);WSARecv(sockList->socketArray[nCurrentIndex],&sockList->overLappedData[nCurrentIndex]->buffer,1,&sockList->overLappedData[nCurrentIndex]->NumberOfBytesRecvd,&sockList->overLappedData[nCurrentIndex]->flags,&sockList->overLappedData[nCurrentIndex]->overlap, NULL);}}return 0;
}int main()
{WSADATA wsa;int nRes = WSAStartup(MAKEWORD(2, 2), &wsa);if (nRes != 0){printf("WSAStartup Error!\r\n");return -1;}SOCKET serverSocket;serverSocket = socket(AF_INET, SOCK_STREAM, 0);if (serverSocket == INVALID_SOCKET){printf("socket Error!\r\n");return -1;}sockaddr_in serverAddr;sockaddr_in clientAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(PORT);serverAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);nRes = bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));if (nRes != 0){printf("bind Error!\r\n");return -1;}nRes = listen(serverSocket, 10);if (nRes != 0){printf("listen Error!\r\n");return -1;}printf("Server Runing!\r\n");int addrLen = sizeof(clientAddr);SOCKET sockConn;SocketListWithIOEvent socketList;HANDLE hThread = CreateThread(NULL, 0, workThread, &socketList, 0, NULL);if (hThread == NULL){printf("CreareThread Failed!\r\n");}CloseHandle(hThread);//这里面,每一个新连接的客服端的第一次数据,是此处while循环里面WSARecv接收数据,后面的数据全部走线程里面接收,如果没有新的客服端连接,此处while循环里面的accept函数将阻塞,不往下执行,一直等待新的客服端连接,当然上一个已经连接的客服端已经由线程一直接受数据while (true){sockConn = accept(serverSocket, (sockaddr*)&clientAddr, &addrLen);if (sockConn == INVALID_SOCKET){printf("accept Failed!\r\n");return -1;}std::cout << "Clinet link:" << inet_ntoa(clientAddr.sin_addr) << ":" << clientAddr.sin_port << std::endl;PerSocketData* overLappedData = socketList.insetSocket(sockConn);WSARecv(sockConn, &overLappedData->buffer, 1, &overLappedData->NumberOfBytesRecvd, &overLappedData->flags, &overLappedData->overlap, NULL);}closesocket(serverSocket);WSACleanup();return 0;
}
客服端:
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <Windows.h>
#include <process.h>void recv(PVOID pt)
{SOCKET sHost = *((SOCKET*)pt);while (true){char buf[64]{ 0 };int nRes = recv(sHost, buf, sizeof(buf), 0);if (nRes == SOCKET_ERROR){int nError = WSAGetLastError();if (nError == WSAEWOULDBLOCK){Sleep(1000);continue;}else if (nError == WSAETIMEDOUT || nError == WSAENETDOWN || nError == WSAECONNRESET){printf("revc failed!\r\n");closesocket(sHost);WSACleanup();return;}}Sleep(100);printf("\r\nrecv:%s", buf);printf("\r\ninput your buffer:\r\n");}
}int main()
{WSADATA wsa;SOCKET sHost;SOCKADDR_IN serverAddr;int nRes;char buf[64]{ 0 };nRes = WSAStartup(MAKEWORD(2, 2), &wsa);if (nRes != 0){printf("WSAStartup Error!\r\n");return -1;}sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(6000);serverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");int sServerAddrlen = sizeof(serverAddr);int iMode = 1;nRes = ioctlsocket(sHost, FIONBIO, (u_long*)&iMode);if (nRes == SOCKET_ERROR){printf("ioctlsocket error!\r\n");WSACleanup();return -1;}printf("clinet runing...\r\n");while (true){nRes = connect(sHost, (SOCKADDR*)&serverAddr, sizeof(serverAddr));if (nRes == SOCKET_ERROR){int nError = WSAGetLastError();if (nError == WSAEWOULDBLOCK || nError == WSAEINVAL){Sleep(1);printf("check!\r\n");continue;}else if (nError == WSAEISCONN){break;}else{printf("connect failed!\r\n");closesocket(sHost);WSACleanup();return -1;}}}unsigned long lThreadid = _beginthread(recv, 0, &sHost);printf("input data:\r\n");while (true){char szBuffer[1024]{ 0 };std::cin >> szBuffer;while (true){nRes = send(sHost, szBuffer, strlen(szBuffer), 0);if (nRes == SOCKET_ERROR){int nError = WSAGetLastError();if (nError == WSAEWOULDBLOCK){Sleep(5);continue;}else{printf("send failed!\r\n");closesocket(sHost);WSACleanup();return -1;}}break;}}return 0;
}
这篇关于WSA重叠IO的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!