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 1024

class 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值