IOCP11 发送字节数

实验一:

        1. Server等待Client连接

        2. Client连接进入,Client等待接收数据

        3. "aaaaaaaaaaaaa"拷入Server发送缓冲区

        4. WSABUF databuf; databuf.len = BUF_LEN;

        5. BUF_LEN自定义宏,值1024

结果:

        Client接收到1024字节数据,15字节"aaaaaaaaaaaaa"和1009字节的无意义数据。


实验二:

        6. 将过程一4中改为WSABUF databuf; databuf.len = 13;

结果:

        Client接收到13字节的"aaaaaaaaaaa“


 

结论:

        投递WSASend和WSASendTo,WSABUF databuf.len值即为此次发送的字节数。(MSDN中于该字段的解释及使用示例有误)


实验一结果图:

     


实验二结果图:

   


实验代码:

Server

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <process.h>
#include <string>
#include <MSWSock.h>
#include <set>
#include "autoLock.h"

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Kernel32.lib")
#pragma comment(lib, "Mswsock.lib")

#define BUF_LEN 1024

enum OperateType
{
	OP_RECV,
	OP_SEND,
	OP_ACCEPT,
};

typedef struct PER_HANDLE_DATA
{
	SOCKET s;
	SOCKADDR_IN addr;
	
	/*参考性添加, 防止重复delete PER_HANDLE_DATA, 目前没有找到更好的办法*/
	HANDLE mutex;
	bool flag;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;

typedef struct PER_IO_DATA
{
	OVERLAPPED overlapped;
	SOCKET cs;
	int no;
	char buf[BUF_LEN]; 
	int operationType;
}PER_IO_DATA, *LPPER_IO_DATA;

SOCKET SocketInitBindListen()
{
	SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
	if(INVALID_SOCKET == s)
	{
		std::cout<<"create socket failed : "<<GetLastError()<<std::endl;
		return INVALID_SOCKET;
	}

	SOCKADDR_IN	addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.S_un.S_addr = INADDR_ANY;
	addr.sin_port = htons(4444);

	int ret = bind(s, (sockaddr*)&addr, sizeof(addr));
	if(SOCKET_ERROR == ret)
	{
		std::cout<<"bind failed : "<<GetLastError()<<std::endl;
		return SOCKET_ERROR;
	}

	ret = listen(s, 10);
	if(SOCKET_ERROR == s)
	{
		std::cout<<"listen fail : "<<GetLastError()<<std::endl;
		return SOCKET_ERROR;
	}

	return s;
}

bool PostAccept(SOCKET listenSocket)
{
	SOCKET cs = socket(AF_INET, SOCK_STREAM, 0);
	if(INVALID_SOCKET == cs)
	{
		std::cout<<"Create Socket Failed : "<<GetLastError()<<std::endl;
		return false;
	}

	LPPER_IO_DATA ppiod = new PER_IO_DATA;
	ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
	ppiod->operationType = OP_ACCEPT;
	ppiod->cs = cs;

	DWORD dwRecv;
	int len = sizeof(sockaddr_in) + 16;
	bool ret = AcceptEx(listenSocket, ppiod->cs, ppiod->buf, 0, len, len, &dwRecv, &ppiod->overlapped);
	if(false == ret && ERROR_IO_PENDING != GetLastError())
	{
		std::cout<<"AcceptEx Failed : "<<GetLastError()<<std::endl;
		return false;
	}

	return true;
}

bool PostSend(SOCKET s, const char *buf, int len)
{
	LPPER_IO_DATA ppiod = new PER_IO_DATA;
	ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
	ppiod->operationType = OP_SEND;
	memset(ppiod->buf, 0, BUF_LEN);
	memcpy(ppiod->buf, buf, len);

	WSABUF databuf;
	databuf.buf = ppiod->buf;
	databuf.len = len;

	DWORD dwRecv = 0;
	DWORD dwFlags = 0;
	int ret = WSASend(s, &databuf, 1, &dwRecv, dwFlags, &ppiod->overlapped, NULL);
	if(SOCKET_ERROR == ret && WSA_IO_PENDING != GetLastError())
		return false;

	return true;
}

bool PostRecv(SOCKET s, int n)
{
	LPPER_IO_DATA ppiod = new PER_IO_DATA;
	ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
	ppiod->operationType = OP_RECV;
	ppiod->no = n;
	memset(ppiod->buf, 0, BUF_LEN);

	WSABUF databuf;
	databuf.buf = ppiod->buf;
	databuf.len = BUF_LEN;

	DWORD dwRecv = 0;
	DWORD dwFlags = 0;
	int ret = WSARecv(s, &databuf, 1, &dwRecv, &dwFlags, &ppiod->overlapped, NULL);
	if(SOCKET_ERROR == ret && WSA_IO_PENDING != GetLastError())
		return false;

	return true;
}

unsigned int __stdcall Func(void *arg)
{
	SOCKET s = (SOCKET)arg;

	PostRecv(s, 2);

	while(std::cin.get())
	{
		std::string str = "nihaihaoma";
		bool ret = PostSend(s, str.c_str(), str.length());
		if(false == ret)
			break;
	}

	_endthreadex(0);
	return 0;
}

unsigned int __stdcall ThreadFunc(void *arg)
{
	HANDLE hcp = (HANDLE)arg;
	if(NULL == hcp)
	{
		std::cout<<"thread arg error"<<std::endl;
		return -1;
	}

	DWORD dwNum = 0;
	LPPER_HANDLE_DATA pphd;
	LPPER_IO_DATA ppiod;
	while(true)
	{
		bool ret = GetQueuedCompletionStatus(hcp, &dwNum, (LPDWORD)&pphd, (LPOVERLAPPED*)&ppiod, WSA_INFINITE);

		//线程退出控制,没有释放申请的堆空间,还不完善
		if(-1 == dwNum)
		{
			std::cout<<"Thread Exit"<<std::endl;
			_endthreadex(0);
			return 0;
		}

		//连接断开
		int type = ppiod->operationType;
		if(0 == dwNum && OP_ACCEPT != type)
		{
			std::cout<<"The Connection Be Closed : "<<GetLastError()<<std::endl;

			//在一个socket上投递多个WSARecv需要考虑连接被Client断开时所有异步WSARecv均返回不会重复delete PER_HANDLE_DATA
			AutoLock lock(pphd->mutex);
			if(true == pphd->flag)
			{
				closesocket(pphd->s);
				delete pphd;
				pphd->flag = false;
			}
			delete ppiod;
			continue;
		}

		//错误发生
		if(false == ret)
		{
			std::cout<<"An Error Occurs : "<<GetLastError()<<std::endl;
			if(pphd != NULL)
			{
				closesocket(pphd->s);
				delete pphd;
			}
			delete ppiod;
			continue;
		}

		if(OP_RECV == type)
		{
			//
			std::cout<<"接收完成"<<std::endl;
			std::cout<<"接收端口号 :"<<pphd->s<<std::endl;
			//

			ppiod->buf[dwNum] = '';
			std::cout<<"Receiver : "<<ppiod->no<<"  "<<ppiod->buf<<std::endl;

			ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
			ZeroMemory(ppiod->buf, BUF_LEN);
			WSABUF databuf;
			databuf.buf = ppiod->buf;
			databuf.len = BUF_LEN;

			DWORD dwRecv = 0;
			DWORD dwFlags = 0;
			WSARecv(pphd->s, &databuf, 1, &dwRecv, &dwFlags, &ppiod->overlapped, NULL);
		}
		else if(OP_SEND == type)
		{
			std::cout<<"发送完成"<<std::endl;
			delete ppiod;
		}
		else if(OP_ACCEPT == type)
		{
			//
			std::cout<<"连接完成"<<std::endl;
			//

			SOCKET cs = ppiod->cs;
			int len = sizeof(sockaddr_in) + 16;
			int localLen, remoteLen;
			LPSOCKADDR localAddr, remoteAddr;
			GetAcceptExSockaddrs(ppiod->buf, 0, len, len, (SOCKADDR **)&localAddr, &localLen, (SOCKADDR **)&remoteAddr, &remoteLen);

			LPPER_HANDLE_DATA p = new PER_HANDLE_DATA;
			p->s = cs;
			memcpy(&p->addr, remoteAddr, remoteLen);
			char *ch = inet_ntoa(p->addr.sin_addr);
			p->mutex = CreateMutex(NULL, false, NULL);
			p->flag = true;

			CreateIoCompletionPort((HANDLE)cs, hcp, (DWORD)p, 0);

			ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
			ppiod->operationType = OP_SEND;
			std::string str("aaaaaaaaaaaaa", 15);
			memcpy(ppiod->buf, str.c_str(), str.length());

			WSABUF databuf;
			databuf.buf = ppiod->buf;
			databuf.len = 13;

			int ret = WSASend(cs, &databuf, 1, NULL, 0, &ppiod->overlapped, NULL);
			if(SOCKET_ERROR == ret && WSA_IO_PENDING != GetLastError())
				return false;

			PostAccept(pphd->s);
		}
	}

	return 0;
}

int main()
{
	WSADATA ws;
	if(WSAStartup(MAKEWORD(2, 2), &ws) != 0)
	{
		std::cout<<"WSAStartup error : "<<GetLastError()<<std::endl;
		return -1;
	}

	HANDLE hcp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
	if(NULL == hcp)
	{
		std::cout<<"create completion port failed : "<<GetLastError()<<std::endl;
		return -1;
	}

	std::set<HANDLE> setWorkers;
	SYSTEM_INFO si;
	GetSystemInfo(&si);
	for(int i = 0; i < si.dwNumberOfProcessors * 2 + 2; i++)
	{
		HANDLE worker = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)hcp, 0, NULL);
		if(NULL == worker)
		{
			std::cout<<"create thread failed : "<<GetLastError()<<std::endl;
			return -1;
		}
		setWorkers.insert(worker);
	}

	SOCKET s = SocketInitBindListen();
	if(INVALID_SOCKET == s)
	{
		std::cout<<"socket init failed"<<std::endl;
		return -1;
	}

	LPPER_HANDLE_DATA pphd = new PER_HANDLE_DATA;
	pphd->s = s;
	CreateIoCompletionPort((HANDLE)s, hcp, (DWORD)pphd, 0);

	bool ret = PostAccept(s);
	if(false == ret)
	{
		std::cout<<"PostAccept Failed"<<std::endl;
		return -1;
	}

	//退出控制
	/*std::cin.get();
	for(int i = 0; i < setWorkers.size(); i++)
		PostQueuedCompletionStatus(hcp, -1, NULL, NULL);*/

	auto iter = setWorkers.begin();
	for(; iter != setWorkers.end(); iter++)
		WaitForSingleObject(*iter, INFINITE);

	WSACleanup();

	std::cin.get();
	return 0;
}
Client

#include <WinSock2.h>
#include <Windows.h>
#include <string>
#include <iostream>

#pragma comment(lib, "Ws2_32.lib")

int main()
{
	WSADATA ws;
	if(WSAStartup(MAKEWORD(2, 2), &ws) != 0)
	{
		printf("WSAStartup != 0, ErrorCode=%d
", GetLastError());
		return 0;
	}

	SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if(INVALID_SOCKET == s)
	{
		printf("socket == INVALID_SOCKET, ErrorCode=%d
", GetLastError());
		return 0;
	}

	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("192.168.4.111");
	addr.sin_port = htons(4444);

	if(SOCKET_ERROR == connect(s, (sockaddr*)&addr, sizeof(addr)))
	{
		printf("connect == SOCKET_ERROR, ErrorCode=%d
", GetLastError());
		return 0;
	}

	char ch[2048] = {0};
	int iRet = recv(s, ch, 2048, 0);
	if(SOCKET_ERROR == iRet)
	{
		printf("recv == SOCKET_ERROR, ErrorCode=%d
", GetLastError());
		return 0;
	}
	if(0 == iRet)
	{
		printf("recv == 0, Connect Closed
");
		return 0;
	}

	for(int i = 0; i != iRet; ++i)
		printf("%c
", ch[i]);
	printf("接收数据长度=%d
", iRet);

	std::cin.get();
	return 0;
}



原文地址:https://www.cnblogs.com/chaikefusibushiji/p/7475606.html