• 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欢迎交流,同时我也会在平时的应用中及时更新发现的问题.

  • 相关阅读:
    java.lang.ClassNotFoundException: org.jaxen.JaxenException
    hdu 4882 ZCC Loves Codefires(贪心)
    C++ STL 源代码学习(之deque篇)
    算法导论学习笔记(2)-归并排序
    机器学习方法:回归(一):线性回归Linear regression
    HDU 2028 Lowest Common Multiple Plus
    C++11新特性应用--实现延时求值(std::function和std::bind)
    大数减法
    hive 运行sqlclient异常
    Oracle 12c agent install for windows
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3074135.html
Copyright © 2020-2023  润新知