Select I/O模型反弹方式的class封装

基于select的I/O模型的封装,采用反弹模式,网络上有很多关于select封装,也与本文的类似,本文只是按照自己的习惯封装了一个类,方便使用.

// SrvSelect.h 
// By LengF 20130506
#include <string>
using namespace std;

#define SOCKET_TIMEOUT -100
class CSrvSelect  
{
public:
	CSrvSelect();
	virtual ~CSrvSelect();
public:
	SOCKET StartConnect(string szHost,UINT nPort);
	int SrvRecv(SOCKET s, char *buf, int len, int flag , int overtime,char*EndMark,BOOL soonflag=FALSE);
	int SrvSend(SOCKET s, const char *buf, int len, int flag,int overtime);
	void ErrorPrint(LPCTSTR lpOutputString );
public:
	SOCKET m_socket;
	BOOL m_bError;
};

下面实现类函数和各种初始化:

// SrvSelect.cpp: implementation of the CSrvSelect class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SrvSelect.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSrvSelect::CSrvSelect()
{
	// Init Socket Library
	WSADATA wsa;
	WSAStartup(MAKEWORD(2,2),&wsa);
	
	// Data Init
	m_socket = INVALID_SOCKET;
	m_bError = TRUE;				// Debug Mode
}

CSrvSelect::~CSrvSelect()
{
	if (m_socket != INVALID_SOCKET)
	{
		closesocket(m_socket);
		shutdown(m_socket,2);
		m_socket = INVALID_SOCKET;
	}
	WSACleanup();
}

void CSrvSelect::ErrorPrint(LPCTSTR lpOutputString)
{
	if (m_bError)
	{
		printf("%s\n",lpOutputString);
		//OutputDebugString(lpOutputString);
	}
}

SOCKET CSrvSelect::StartConnect(string szHost, UINT nPort)
{
	SOCKET s = INVALID_SOCKET;
	SOCKADDR_IN ClientAddr;
	LPHOSTENT Host;		// for DNS
	memset(&ClientAddr,0,sizeof(SOCKADDR_IN));

	if (szHost.empty() || nPort ==0)	// Params Error
		return INVALID_SOCKET;

	Host=gethostbyname(szHost.c_str());

	ClientAddr.sin_family = AF_INET;
	ClientAddr.sin_port = htons((u_short)nPort);	// Host Port
	ClientAddr.sin_addr = *((LPIN_ADDR)*Host->h_addr_list); // Host IP
	// create socket
	// PF_INET for IPV6,IPV4
	s = socket(PF_INET,SOCK_STREAM,0);

	if(connect(s,(LPSOCKADDR)&ClientAddr,sizeof(ClientAddr)) == SOCKET_ERROR) // connect error
	{
		ErrorPrint("[s] Connect Error.");
		closesocket(s);
		shutdown(s,2);
		s = INVALID_SOCKET;
	}
	m_socket = s;

	return s;
}

int CSrvSelect::SrvSend(SOCKET s, const char *buf, int len, int flag, int overtime)
{
	int		ret;
	int		nLeft = len;
	int		idx	 = 0;
	
	fd_set readfds;
	struct timeval  timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 500;
	DWORD s_time = GetTickCount();
	
	while ( nLeft > 0 )
	{
		MSG msg;
		PeekMessage(&msg, NULL,  0, 0, PM_REMOVE) ;
		if(msg.message == WM_QUIT)
			return 0;
		
		FD_ZERO( &readfds );
		FD_SET( s , &readfds );
		
		int errorret   = select( 0 , NULL, &readfds, NULL , &timeout );
		
		if( errorret == SOCKET_ERROR )
		{
			ErrorPrint("[s] Socket select error.");
			return SOCKET_ERROR;
		}
		
		DWORD e_time = GetTickCount( );
		if  ( !FD_ISSET( s , &readfds ) )
		{
			
			if( e_time - s_time > overtime*1000 ) 
			{
				ErrorPrint("[s] Send Data TimeOut.");
				return 0;
			}
			else
			{
				continue;
			}
		}
		
		ret = send( s, &buf[idx], nLeft, flag );
		
		if ( ret <= 0 )
		{
			return ret;
		}
		
		nLeft	-= ret;
		idx		+= ret;
	}	// end while
	
	return len;
}

int CSrvSelect::SrvRecv(SOCKET s, char *buf, int len, int flag, int overtime, char *EndMark, BOOL soonflag)
{
	int		ret;
	int		nLeft = len;
	int		idx	 = 0;
	int		nCount = 0;
	fd_set readfds;
	struct timeval  timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 500;
	DWORD s_time = GetTickCount();
	
	while ( nLeft > 0 )
	{
		MSG msg;
		PeekMessage(&msg, NULL,  0, 0, PM_REMOVE) ;
		if(msg.message == WM_QUIT)
			return 0;
		
		FD_ZERO( &readfds );
		FD_SET( s , &readfds );
		if( select( 0 , &readfds , NULL , NULL , &timeout ) == SOCKET_ERROR )
		{
			return SOCKET_ERROR;
		}
		
		DWORD e_time = GetTickCount( );
		if  ( !FD_ISSET( s , &readfds ) )
		{
			if( e_time - s_time > overtime*1000 ) 
				return SOCKET_TIMEOUT;
			else
				continue;
		}
		
		ret = recv( s, &buf[idx], nLeft, flag );
		
		if( soonflag == TRUE )
		{
			return ret;
		}
		
		s_time = e_time ; // reset time 
		
		if ( ret <= 0 )
		{
			int		LastError = GetLastError();
			if ( ( -1 == ret ) && ( WSAETIMEDOUT	  == LastError ) )
				continue;
			if ( ( -1 == ret ) && ( WSAEWOULDBLOCK	  == LastError ) )
			{
				if ( nCount < 2000 )
				{
					Sleep( 10 );
					nCount++;
					continue;
				}
			}
			return ret;
		}
		nCount	=	0;
		
		nLeft	-= ret;
		idx		+= ret;
		
		if( EndMark != NULL && idx>5)
		{
			if( strstr(buf+(idx-5),EndMark) != NULL )
			{
				break;
			}
		}
	}// end while
	
	return idx;
}

至此整个类的封装已经完成了.如果有什么想法,或者BUGS欢迎交流,同时我也会在平时的应用中及时更新发现的问题.

原文地址:https://www.cnblogs.com/javawebsoa/p/3074135.html