纯重叠io服务器模型

版权声明: https://blog.csdn.net/dashoumeixi/article/details/86495818

基础:套接字重叠io

客户端: telnet 或者自己随意写一个;

纯重叠实现的服务器模型,基本上就是使用OVERLAPPED和APC函数完成.

APC函数即需要使用alterable状态的函数 , 例 SleepEx.

另外重叠io与非阻塞是2个概念.

下面的代码中使用到了非阻塞io, 仅仅作用在了accept上. 让其不阻塞;

这种纯重叠io模型的服务器缺点是既要accept,又要让线程进入alterab;e状态

这个例子同时解释了非阻塞io. 和重叠io : 可以把设置非阻塞的函数注释.看看效果



#include "stdafx.h"
#include "../utils.h"
#define BUFFSIZE 8192


//自定义一块数据. 用于放入OVERLAPPED的Event中,以便传入APC
typedef struct{
	SOCKET hSocket;
	WSABUF wsabuf;
	char buf[BUFFSIZE];
} PER_DATA , *PPER_DATA;

void CALLBACK WriteRouine(IN DWORD dwError,IN DWORD cbTransferred,IN LPWSAOVERLAPPED lpOverlapped,IN DWORD dwFlags);

//读取 - APC
void CALLBACK ReadRoutine(
	IN DWORD dwError,
	IN DWORD cbTransferred,
	IN LPWSAOVERLAPPED lpOverlapped,
	IN DWORD dwFlags
	){
	printf("readRoutine , error:%ld \t bytesRead : %ld \tflags:%ld", dwError, cbTransferred, dwFlags);
	PPER_DATA pData = (PPER_DATA)lpOverlapped->hEvent;

    //如果对端EOF
	if (cbTransferred == 0) {
		closesocket(pData->hSocket);
		free(lpOverlapped->hEvent);
		free(lpOverlapped);
		puts("peer closed!!");
	}
	else{

    //否则回传
		pData->wsabuf.len = cbTransferred;
   //最后一个参数传递, write routine。 即接受完发送数据,发送数据完,等待再次接受
		WSASend(pData->hSocket, &pData->wsabuf, 1, NULL, 0, lpOverlapped, WriteRouine);
		puts("send data;");
	}

}

//写入 - APC
void CALLBACK WriteRouine(
	IN DWORD dwError,
	IN DWORD cbTransferred,
	IN LPWSAOVERLAPPED lpOverlapped,
	IN DWORD dwFlags
	){
	DWORD flag = 0;
	printf("WriteRouine , error:%ld \t bytesRead : %ld \tflags:%ld", dwError, cbTransferred, dwFlags);
	PPER_DATA pData = (PPER_DATA)lpOverlapped->hEvent;

    //写完后等待再次接受数据
	WSARecv(pData->hSocket, &pData->wsabuf, 1, NULL, &flag, lpOverlapped, ReadRoutine);
	puts("recv data");
}


//设置非阻塞
int setNonBlockMode(SOCKET sock,u_long bEnable)
{
	return ioctlsocket(sock, FIONBIO, &bEnable);
}

int _tmain(int argc, _TCHAR* argv[])
{
	WSAData wsadata;
	if (WSAStartup(MAKEWORD(2, 2), &wsadata) == SOCKET_ERROR){
		print_error(WSAGetLastError());
		return 0;
	}
	SOCKET hListenSocket =WSASocket(AF_INET, SOCK_STREAM, 0, NULL, NULL, WSA_FLAG_OVERLAPPED);

    //设置监听socket为非阻塞.可以把这一行注释掉,这样就将阻塞在accept上了
	setNonBlockMode(hListenSocket, TRUE);
	SOCKADDR_IN serv_addr, client_addr;
	memset(&serv_addr, 0, sizeof(serv_addr));
	memset(&client_addr, 0, sizeof(client_addr));
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);

	if (SOCKET_ERROR == bind(hListenSocket, (SOCKADDR*)&serv_addr, sizeof(serv_addr))){
		print_error(WSAGetLastError());
		return 0;
	}

	if (SOCKET_ERROR == listen(hListenSocket, BACKLOG)){
		print_error(WSAGetLastError());
		return 0;
	}
	int client_addr_size = sizeof(client_addr) , error = 0 , ret = 0;
	SOCKET hClientSock = NULL;
	PPER_DATA client_info = NULL;
	WSAOVERLAPPED * pOver = NULL;
	DWORD flags = 0, recvBytes = 0;;



	while (1)
	{
		flags = 0;
		ret = SleepEx(1000, TRUE);  // alterable状态
		if (ret == WAIT_IO_COMPLETION){    //一旦routine完成将返回这个信息
			puts("\t io completed");
		}
		client_addr_size = sizeof(client_addr);

		hClientSock = accept(hListenSocket, (SOCKADDR*)&client_addr, &client_addr_size);

        //由于是非阻塞套接字,因此需要判断是否真的有连接进入
		if (INVALID_SOCKET == hClientSock){
			error = WSAGetLastError();

             //这个错误信息是非阻塞的典型错误
			if (error == WSAEWOULDBLOCK)
				puts("no connection");
			continue;
		}

        //创建一个OVERLAPPED结构
		pOver =(LPWSAOVERLAPPED) malloc(sizeof(WSAOVERLAPPED));
		memset(pOver, 0, sizeof(WSAOVERLAPPED));

        //创建一块自定义数据
		client_info = (PPER_DATA)malloc(sizeof(PER_DATA));
		client_info->hSocket = hClientSock;
		client_info->wsabuf.buf = client_info->buf;
		client_info->wsabuf.len = BUFFSIZE;

        //由于使用了APC,hEvent可以自由分配
		pOver->hEvent = (HANDLE)client_info;
    
        //接受数据,无论是否是非阻塞 与 OVERLAPPED 无关
		ret = WSARecv(hClientSock, &client_info->wsabuf, 1, &recvBytes, &flags, pOver, ReadRoutine);
		if (0 == ret){
			printf("recv quickly , recvBytes:%ld\n", recvBytes);
		}
		else {
			error = WSAGetLastError();
			if (WSA_IO_PENDING == error)
				puts("**** pending *** ");
			else
				print_error(error);
		}
	}




	WSACleanup();


	return 0;
}

猜你喜欢

转载自blog.csdn.net/dashoumeixi/article/details/86495818