非阻塞I/O模型的测试

  1. 客户端代码:
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdlib.h>
#include<stdio.h>
#include<iostream>
using namespace std;

#pragma comment(lib,"ws2_32.lib")
#define DEF_PORT	27015
#define DEF_SIZE	512

int main()
{
	WSADATA wsaData;
	SOCKET ConnectSocket = INVALID_SOCKET;
	int iResult;
	//初始化Winsock
	iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
	if(iResult != 0){
		cout<<"WSAStartup failed with error: "<<iResult<<endl;
        return 1;
	}

	//创建用于连接的socket
	
	ConnectSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);

	if(ConnectSocket == INVALID_SOCKET){
		cout<<"socket created with error: "<<GetLastError()<<endl;
		WSACleanup();
		return 1;
	}
	
	//连接
	sockaddr_in addserver;
	addserver.sin_family = AF_INET;
	addserver.sin_port = htons(DEF_PORT);
	addserver.sin_addr.S_un.S_addr = inet_addr("10.50.92.211");

	//连接
	iResult  = connect(ConnectSocket,(const sockaddr*)&addserver,sizeof(addserver));
	if(iResult != 0){
		printf("connect failed with error :%d\n",GetLastError());
		closesocket(ConnectSocket);
		WSACleanup();
		return 1;
	}
	char sendbuf[DEF_SIZE];
	printf("conntect successful...\n");
	printf("Please input sendbuf:");
	cin>>sendbuf;
	//发送数据
	iResult = send(ConnectSocket,sendbuf,sizeof(sendbuf),0);
	if(iResult > 0){
		printf("host send: %s\n",sendbuf);
	}
	closesocket(ConnectSocket);
	WSACleanup();
	system("pause");
	return 0;
}
  1. 非阻塞I/O模型服务器代码:
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdlib.h>
#include<stdio.h>
#include<iostream>
using namespace std;

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

#define DEF_PORT	27015
#define DEF_SIZE	512


int main()
{
	WSADATA wsaData;
	int iResult;
	SOCKET ListenSocket = INVALID_SOCKET;
	SOCKET AcceptSocket = INVALID_SOCKET;
	

	//1.初始化
	iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
	if(iResult != 0)
	{
		printf("WSAStartup failed with error :%d\n",iResult);
		return 1;
	}

	//2.创建用于监听的套接字
	ListenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
	if(ListenSocket == INVALID_SOCKET){
		printf("create ListenSocket failed with error:%d\n",GetLastError());
		WSACleanup();
		return 1;
	}
	//3.为监听套接字绑定地址和端口号
	sockaddr_in addServer;

	addServer.sin_family = AF_INET;
	addServer.sin_port = htons(DEF_PORT);
	addServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

	iResult = bind(ListenSocket,(const sockaddr*)&addServer,sizeof(addServer));
	if(iResult == SOCKET_ERROR){
		printf("bind failed with error:%d",GetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	//4.设置套接字为非阻塞模式
	int iMode = 1;
	iResult = ioctlsocket(ListenSocket,FIONBIO,(u_long*)&iMode);
	if(iResult == SOCKET_ERROR)
	{
		printf("ioctlsocket failed with error: %d\n",GetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}


	/*5.监听客户端的连接
		如果设置为SOMAXCONN,则负责套接字的底层服务提供程序会将backlog设置为最大合理值。*/
	iResult = listen(ListenSocket,SOMAXCONN);
	if(iResult == SOCKET_ERROR){
		printf("Listen failed with error:%d\n",GetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}
	printf("TCP Server is starting...\n");

	sockaddr_in addClient;
	int addClient_Size = sizeof(addClient);
	char recvbuf[DEF_SIZE] = {0};
	int  recvlen = sizeof(recvbuf);
	//循环等待客户请求建立连接,并处理连接请求
	while(1){
		//因为是非阻塞模式,必然会返回
		AcceptSocket = accept(ListenSocket,(sockaddr*)&addClient,&addClient_Size);	
		if(AcceptSocket == INVALID_SOCKET){
			iResult = WSAGetLastError();
			if(iResult == WSAEWOULDBLOCK)
			{
				Sleep(1000);	//1000ms
				printf("等待连接中...........\n");
				continue;
			}
			else {
				printf("accpet failed!\n");
				closesocket(ListenSocket);
				WSACleanup();
				return 1;
			}
		}
		printf("收到新的连接:%s\n",inet_ntoa(addClient.sin_addr));
		//循环接收数据
		while(1){
			memset(recvbuf,0,sizeof(recvbuf));
			iResult = recv(AcceptSocket,recvbuf,recvlen,0);
			if(iResult > 0){
				printf("数据内容: %s\n",recvbuf);
				//跳出轮询接收
				continue;
			}
			else if(iResult == 0){		//返回值0代表正常关闭	
				printf("客户端已经正常关闭....\n");
				closesocket(AcceptSocket);
				break;
			}
			else{	//接收出现错误

				iResult = WSAGetLastError();
				if(iResult == WSAEWOULDBLOCK)
				{
					//无法立即完成非阻塞socket上的操作
					Sleep(1000);	//1000ms
					printf("当前I/O不满足,等待毫秒轮询\n");
					continue;
				}
				else {
					printf("recv failed with error: %d\n",GetLastError());
					closesocket(AcceptSocket);
					closesocket(ListenSocket);
					WSACleanup();
					return 1;
				}
			}
		}
	}
	closesocket(AcceptSocket);
	closesocket(ListenSocket);
	WSACleanup();
	system("pause");
	return 0;
}
  1. 测试结果
    在这里插入图片描述
  2. 模型评价

非阻塞I/O模型使用简单的方法来避免套接字在某个I/O操作上阻塞等待,应用进程不再睡眠等待,而是可以在等待I/O条件满足的这段时间内做其他的事情。在函数轮询的间隙可以对其他套接字的I/O操作进行类似的尝试,对于多个套接字的网络I/O可以避免串行等待带来的效率低下问题。
缺点:由于应用程序不断尝试接口函数的调用,直到成功完成指定的操作,cpu的利用效率很低。此外如果设置了较长的延迟实际按,则最后一次成功的I/O操作对于I/O事件发生来讲有滞后事件,所以不适用于对实时性要求高的应用。

猜你喜欢

转载自blog.csdn.net/bryant_xw/article/details/88917331