Visual C ++ Programming Learning Network (3) - Ready Notice I / O model

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/weixin_43165699/article/details/100151495

Visual C ++ Programming Learning Network (3) - Ready Notice I / O model (select)

       Prior to this, we built a model obstruction blocking TCP and UDP model of. After doing a little feel secretly delighted, but later found to still have a few questions:
       1. Before we build are blocking I / O model that when using accept, Receive function, if no data is reached, the current thread will remain blocked at this time will have some impact on other operations. But if the socket is set within the model is non-blocking, to accept, calling the timing Receive function without a good grasp.
       2. For server program, how to support multiple client connections.
       For these problems, select the model can be a good solution.
      First, select can help us determine our status detection system, when the condition that the response of the I / O operation has been met, it will notify the calling thread I / O functions, then the general can ensure success without blocking occurs. Secondly, you can select a variety of operating simultaneously detect multiple sockets, so any socket operation ready, select will notice, that is to say can wait select models with multiple operating simultaneously on more than one socket Ability.
      It will now be published as follows server code, client code directly from the client code can https://blog.csdn.net/weixin_43165699/article/details/100066402.
#include<iostream>
#include<WINSOCK2.h>
#include <vector>
#include <string>//引用头文件
#pragma comment(lib,"Ws2_32.lib")
using namespace std;
#define SERVEPORT 10000
#define nBuffersize 10000
#define CLIENTNUMBERMAX 64 
#define nBuffsize 1000
struct Connection
{
	int numberClient;
	SOCKET hsocket;
	char Buffer[nBuffersize];
	int nBytes;
	Connection(int numberClient,SOCKET socket) :numberClient(numberClient),hsocket(socket), nBytes(0) {}
};
typedef vector<Connection *> Connectionlist;
SOCKET BindListen();           
int DoWork();                 
void ResetFDSet(fd_set& fdRead, fd_set& fdWrite, fd_set& fdExcept, SOCKET SocketServe, Connectionlist &conns);
int CheckAccept(fd_set& fdRead, fd_set& fdWrite, fd_set& fdExcept, SOCKET SocketServe, Connectionlist &conns);
void CheckClientConnection(fd_set& fdRead, fd_set& fdWrite, fd_set& fdExcept, Connectionlist &conns);
bool Read(Connection *PConn);
void GetTime();              
bool SendClientMes(Connectionlist &conns);
void ThreadFunc();           
static Connectionlist conns;
static int ClientNumber;  

SOCKET BindListen()
{
	WSADATA wsaData = { 0 };
	WORD wVer = MAKEWORD(2, 2);
    if (0 != WSAStartup(wVer, &wsaData))
	{
	GetTime();
	 cout << "初始化错误,错误代码:" << WSAStartup(wVer, &wsaData) << endl;
	 return 0;
	}
	SOCKET SocketServe=NULL;
	if (NULL != SocketServe)	
	{
	closesocket(SocketServe);
	}
	SocketServe = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == SocketServe)
	{
	GetTime();
	cout << "创建套接字错误,错误代码:" << WSAGetLastError() << endl;
	return 0;
      }
	GetTime();
	cout << "套接字创建成功!" << endl;
	sockaddr_in soServeAddr;         //服务器地址

	soServeAddr.sin_family = AF_INET;
	soServeAddr.sin_port = htons(SERVEPORT);
	soServeAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
		
	if (bind(SocketServe, (sockaddr*)&soServeAddr, sizeof(soServeAddr)))
	{
	GetTime();
	cout << "套接字绑定错误,错误代码" << WSAGetLastError() << endl;
	return 0;
	}
	if (listen(SocketServe, CLIENTNUMBERMAX) == SOCKET_ERROR)
	{
	GetTime();
	cout << "监听失败" << WSAGetLastError() << endl;
	return 0;
		}
	GetTime();
	cout << "服务器端已启动等待连接..." << endl;
	return SocketServe;
}
int  DoWork()
{
	SOCKET SocketServe = BindListen();
    u_long nNoBlock = 1;
	if (ioctlsocket(SocketServe,FIONBIO,&nNoBlock)==SOCKET_ERROR)
	{
	GetTime();
	 cout << "套接字模式设置失败,错误代码:" << WSAGetLastError() << endl;
	 return 0;
		}
	fd_set fdRead, fdWrite, fdExcept;
	ClientNumber = 0;
	while (true)
	{
		ResetFDSet(fdRead, fdWrite, fdExcept,SocketServe,conns);
		int nRet = select(0,&fdRead,&fdWrite,&fdExcept,NULL);
		if (nRet<=0)
		{
			GetTime();
			cout << "select error" << WSAGetLastError() << endl;
			break;
		}
		nRet = CheckAccept(fdRead, fdWrite, fdExcept,SocketServe,conns);
		if (nRet==SOCKET_ERROR)
		{
			break;
		}
		CheckClientConnection(fdRead, fdWrite, fdExcept,conns);
	}
	Connectionlist::iterator it = conns.begin();
	for (; it!=conns.end(); ++it)
	{
		closesocket((*it)->hsocket);
		delete *it;
	}
	ClientNumber = 0;
	if (SocketServe!=INVALID_SOCKET)
	{
		closesocket(SocketServe);
	}
	return 0;
}
void ResetFDSet(fd_set& fdRead, fd_set& fdWrite, fd_set& fdExcept, SOCKET SocketServe, Connectionlist &conns)
{
    FD_ZERO(&fdRead);
	FD_ZERO(&fdWrite);
	FD_ZERO(&fdExcept);
	FD_SET(SocketServe, &fdRead);
	FD_SET(SocketServe, &fdExcept);

	Connectionlist::iterator it = conns.begin();
	for (; it!= conns.end();++it)
	{
		Connection *pConn = *it;
	    FD_SET(pConn->hsocket, &fdRead);
		FD_SET(pConn->hsocket, &fdExcept);
	}
}
int CheckAccept( fd_set & fdRead,  fd_set & fdWrite,  fd_set & fdExcept, SOCKET SocketServe, Connectionlist &conns)
{

	int lastErr = 0;
	if (FD_ISSET(SocketServe,&fdExcept))
	{
		int errlen = sizeof(lastErr);
		getsockopt(SocketServe,SOL_SOCKET,SO_ERROR,(char*)&lastErr,&errlen);
		GetTime();
		cout << "I/O error" << lastErr << endl;
		return SOCKET_ERROR;
	}
	if (FD_ISSET(SocketServe,&fdRead))
	{
		sockaddr_in soClientAddr;
		int nSize = sizeof(soClientAddr);
		SOCKET sd = accept(SocketServe,(sockaddr*)&soClientAddr, &nSize);
		lastErr = WSAGetLastError();
		if (sd==INVALID_SOCKET&&lastErr!=WSAEWOULDBLOCK)
		{
			cout << "accept error" << lastErr << endl;
			return SOCKET_ERROR;
		}
		if (sd!=INVALID_SOCKET)
		{
			u_long nNoBlock = 1;
			if (ioctlsocket(sd, FIONBIO, &nNoBlock) == SOCKET_ERROR)
			{
				GetTime();
				cout << "套接字模式设置失败,错误代码:" << WSAGetLastError() << endl;
				return SOCKET_ERROR;
			}
			ClientNumber++;
			conns.push_back(new Connection(ClientNumber,sd));
			GetTime();
			cout <<"第【"<< ClientNumber<< "】个套接字连接成功"<< endl;
		}
	}
	return 0;
}
void CheckClientConnection(fd_set & fdRead, fd_set & fdWrite, fd_set & fdExcept, Connectionlist &conns)
{
	Connectionlist::iterator it = conns.begin();
	while (it!=conns.end())
	{
		Connection * pConn = *it;
		bool BOK = true;
		if (FD_ISSET(pConn->hsocket, &fdExcept))
		{
			BOK = false;
			int lastErr;
			int errlen = sizeof(lastErr);
			getsockopt(pConn->hsocket, SOL_SOCKET, SO_ERROR, (char *)&lastErr, &errlen);
			GetTime();
			cout << "I/O 错误" << lastErr << endl;
		}
		else
		{
			if (FD_ISSET(pConn->hsocket, &fdRead))
			{
				BOK = Read(pConn);
			}
			else if (FD_ISSET(pConn->hsocket, &fdWrite))
			{
				//BOK = TryWrite(pConn);
			}
		}
		if (BOK==false)
		{
			ClientNumber--;                        //客户端数量减少
			closesocket(pConn->hsocket);
			delete pConn;
			it = conns.erase(it);
		}
		else
		{
			++it;
		}
	}
}
bool Read(Connection * PConn)
{
	int nRet = recv(PConn->hsocket, PConn->Buffer, nBuffersize,0);
	if (nRet>0)
	{
		GetTime();
		cout <<"第【"<< PConn->numberClient<< "】个客户端接收到数据:";
		for (int  i = 0; i < nRet; i++)
		{
			cout << *(PConn->Buffer + i);
		}
		cout << " "<<endl;
		return true;
	}
	else if (nRet == 0)
	{
		GetTime();
		cout << "第【" << PConn->numberClient << "】个客户端连接已经断开" << endl;
		return false;
	}
	else
	{
		int lastErr = WSAGetLastError();
		if (lastErr==WSAEWOULDBLOCK)
		{
			return true;
		}
		GetTime();
		cout << "第【" << PConn->numberClient << "】个客户端连接已经断开" << endl;
		return false;
	}
	return false;
}
void GetTime()
{
	SYSTEMTIME st;
	GetLocalTime(&st);
	cout << st.wYear << ":" << st.wMonth << ":" << st.wDay << ":" << st.wHour << ":" << st.wMinute << ":" << st.wSecond<<"  ";
}
bool SendClientMes(Connectionlist &conns)
{
	int number;
	GetTime();
	cout << "请输入客户端号:" ;
	cin >> number;
	cout <<" "<<endl;
	if (number>ClientNumber)
	{
		GetTime();
		cout << "该客户端当前未连接" << endl;
		return false;
	}
	else
	{
		Connectionlist::iterator it = conns.begin();
	
		while ((*it)->numberClient<= number)
		{
			if ((*it)->numberClient==number)
			{
				GetTime();
				cout << "请输入你要发送的数据:";
				string s1;
				cin >> s1;
				int buffsize = nBuffersize;
				char *revBuffer = (char*)malloc(sizeof(char)*buffsize);
				int i = 0;
				for (i = 0; i < s1.size(); i++)
				{
					*(revBuffer + i) = s1[i];
				}
				int nSent = send((*it)->hsocket, revBuffer, i, 0);

				if (nSent>0)
				{
					if (nSent == i)
					{
						GetTime();
						cout << "第【" << (*it)->numberClient << "】个客户端数据已经发送,发送正常。" << endl;
					}
					else
					{
						GetTime();
						cout << "第【" << (*it)->numberClient << "】个客户端数据未发完。" << endl;
					}
					return true;
				}
				else if (nSent == 0)
				{
					GetTime();
					cout << "第【" << (*it)->numberClient << "】个客户端连接已经断开" << endl;
					return false;
				}
				else
				{
					int lastErr = WSAGetLastError();
					if (lastErr == WSAEWOULDBLOCK)
					{
						return true;
					}
					GetTime();
					cout << "第【" << (*it)->numberClient << "】个客户端连接已经断开" << endl;
					return false;
				}
			}
			it++;
		}

	}
	return true;
}
void ThreadFunc()
{
	DoWork();
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
void main()
{
	cout << "************************服务器测试程序************************"<<endl;
	HANDLE hThread;
	DWORD ThreadID;
	hThread = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&ThreadID);
	while (true)
	{
		int t;
		cin >> t;
		switch (t)
		{
		case 1:
		{
			SendClientMes(conns);
			break;
		}
		default:
		{
			break;
		}
			
		}
		
	}
}

Here are the results and client interaction:
Here Insert Picture Description

Guess you like

Origin blog.csdn.net/weixin_43165699/article/details/100151495