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

浙公网安备 33010602011771号