Programación de sockets ~~Urgente~~~
Clase de descarga HTTP encapsulada por socket
//HttpDownload.h
#ifndef _HTTPDOWNLOAD_H
#define _HTTPDOWNLOAD_H
//#include "InitSock.h"
//CInitSock estático initsock;
/****************** * ************************************************** ****
Descripción: clase de codificación y decodificación Base64
Función: se puede utilizar para resolver: 81/index.html#link1
/// p>
//////////////////////////////////////////// ///// //////////////////
// Buscar si hay un número de puerto
nPos = strTemp. Find(":");
if( nPos == -1 )
{
strServer = strTemp;
nPort = CHttpDownload::DEFAULT_PORT;
}
else
{
strServer = strTemp.Left( nPos );
strTemp = strTemp.Mid( nPos+1 );
nPort = _ttoi((LPCTSTR)strTemp);
}
devuelve verdadero; p>
} p>
#endif
//HttpDownload.cpp
#include "StdAfx.h"
#include "HttpDownload.h"
/*************************************** *********** ****************************
***** ************* ************************************* ************** ******/
int CBase64::s_nBase64Mask[] = {0, 1, 3, 7, 15, 31, 63 , 127, 255};
CString CBase64::s_strBase64TAB = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
int CBase64::Base64Decode(LPCTSTR lpszDecoding, CString& strDecoded) p>
{
int nIndex = 0;
int nDigit;
int nDecode[ 256 ];
int nSize;
int nNumBits = 6;
if( lpszDecoding == NULL )
devuelve 0;
if(
( nSize = lstrlen(lpszDecoding) ) == 0 )
return 0;
// Construir tabla de decodificación
for( int i = 0; i < 256; i++ )
nDecode[i] = -2; // Dígito ilegal
for( i=0; i < 64; i++ )
{
nDecode[ s_strBase64TAB[ i ] ] = i;
nDecode[ '=' ] = -1
}
/ / Borrar el buffer de salida
strDecoded = _T("");
long lBitsStorage =0;
int nBitsRemaining = 0;
int nScratch = 0;
UCHAR c;
// Decodifica la entrada
for( nIndex = 0, i = 0; nIndex < nSize; nIndex++ )
{
c = lpszDecoding[ nIndex ];
// Ignora todos los caracteres ilegales
if( c> 0x7F )
continuar;
nDigit = nDecode[c];
if( nDigit >= 0 )
{
lBitsStorage = (lBitsStorage << nNumBits) | (nDigit & 0x3F);
nBitsRemaining += nNumBits;
while( nBitsRemaining > 7 )
{
nScratch = lBitsStorage >> (nBitsRemaining - 8);
strDecoded += (nScratch & 0xFF);
i++;
nBitsRemaining -= 8;
}
}
}
return strDecoded.GetLength();
}
int CBase64::Base64Encode(LPCTSTR lpszEncoding, CString& strEncoded)
{
int nDigit;
int nNumBits = 6 ;
int nIndex = 0;
int nInputSize;
strEncoded = _T( "" );
if( lpszEncoding == NULL )
devuelve 0;
if( ( nInputSize = lstrlen(lpszEncoding) ) == 0 )
devuelve 0;
int nBitsRemaini
ng = 0;
long lBitsStorage = 0;
long lScratch = 0;
int nBits;
UCHAR c; p> p>
while( nNumBits > 0 )
{
while( ( nBitsRemaining < nNumBits ) && ( nIndex < nInputSize ) )
{ p>
c = lpszEncoding[ nIndex++ ];
lBitsStorage <<= 8;
lBitsStorage |= (c & 0xff);
nBitsRemaining + = 8;
}
if( nBitsRemaining < nNumBits )
{
lScratch = lBitsStorage << ( nNumBits - nBitsRemaining
nBits = nBitsRemaining;
nBitsRemaining = 0;
}
else
{ p>
lScratch = lBitsStorage >> ( nBitsRemaining - nNumBits );
nBits = nNumBits;
nBitsRemaining -= nNumBits;
}
nDigit = (int)(lScratch & s_nBase64Mask[nNumBits]);
nNumBits = nBits;
if( nNumBits <=0 )
break;
strEncoded += s_strBase64TAB[ nDigit ];
}
// Rellenar con '=" según RFC 1521
while( strEncoded.GetLength() % 4 != 0 )
strEncoded += '=';
return strEncoded.GetLength();
}
/********************************************* ***** ****************************
*********** ******* ******************************************* ******** ******/
CHttpDownload::CHttpDownload():
m_hSocket(INVALID_SOCKET),
m_nResponseHeaderSize( 0)
{
memset(m_szRequestHeader, 0, sizeof(m_szRequestHeader));
memset(m_szResponseHeader, 0,
sizeof(m_szResponseHeader));
}
CHttpDownload::~CHttpDownload()
{
CloseSocket();
}
bool CHttpDownload::CreateSocket()
{
CloseSocket();
m_hSocket = socket(AF_INET , SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == m_hSocket)
{
devuelve falso;
}
devuelve verdadero;
}
void CHttpDownload::CloseSocket()
{
if (INVALID_SOCKET != m_hSocket )
{
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
}
void CHttpDownload::FormatRequestHeader(const char* pszServer, int nPort, const char* pszObject, const char *pAuthorization /* = NULL */)
{
memset (m_szRequestHeader, '\0', 1024);
//Línea 1: Método de solicitud, ruta, versión
strcat(m_szRequestHeader, "GET ");
strcat(m_szRequestHeader, pszObject);
strcat(m_szRequestHeader, " HTTP/1.0");
strcat(m_szRequestHeader, "\r\n"); p>
//Línea 2: Tipo de datos solicitado
strcat(m_szRequestHeader, "Accept: */*");
strcat(m_szRequestHeader, "\r\ n");
//Línea 3: host, puerto
char szPort[10];
sprintf(szPort, ":%d", nPort); p>
strcat(m_szRequestHeader, "Host: ");
strcat(m_szRequestHeader, pszServer);
strcat(m_szRequestHeader, szPort);
p>strcat(m_szRequestHeader, "\r\n");
//Línea 4: control de búfer
strcat(m_szRequestHeader, "Catch-control: no-cache");
strcat(m_szRequestHeader, "\r\n");
//Línea 5: Permisos de acceso
if (pAutorización)
{
CStri
ng strAuth;
strcat(m_szRequestHeader, "Autorización: Básica ");
CBase64::Base64Encode(pAuthorization, strAuth);
strcat(m_szRequestHeader, strAuth );
strcat(m_szRequestHeader, "\r\n");
}
//Última línea: línea en blanco
strcat(m_szRequestHeader, "\r\n");
}
bool CHttpDownload::SendRequest()
{
int len = strlen(m_szRequestHeader);
//if(send(m_hSocket,m_szRequestHeader,len,0)==SOCKET_ERROR)
//{
/ / return false;
//}
if (SelectSend(m_szRequestHeader, len ,DEFAULT_SENDTIMEOUT) <= 0)
{
devolver falso;
}
if (!GetResponseHeader())
{
devolver falso;
}
devuelve verdadero;
}
bool CHttpDownload::Connect(const char* pszHostIP, int nPort /* DEFAULT_PORT */, long ltimeout /* DEFAULT_CONNECTTIMEOUT */)
{
ASSERT(pszHostIP);
sockaddr_in addr;
memset( &addr, 0, sizeof(addr) );
addr.sin_family = AF_INET;
addr.sin_port = htons(nPort);
addr.sin_addr.S_un.S_addr = inet_addr(pszHostIP) ;
unsigned long ul = 1;
int ret = ioctlsocket(m_hSocket, FIONBIO, (unsigned long*)&ul);
if( ret == SOCKET_ERROR)
{
return false;
}
connect(m_hSocket, (sockaddr*)&addr, sizeof(addr)) ;
timeval timeout = { 1, ltimeout };
fd_set r
FD_ZERO(&r); &r);
ret = seleccionar(0, 0,
&r, 0, &timeout);
if( ret <= 0 )
{
return false;
}
// Generalmente, los sockets en modo sin bloqueo son difíciles de controlar. Puede considerar volver al modo de bloqueo según la situación real.
unsigned long ul1=
ret = ioctlsocket( m_hSocket, FIONBIO, (unsigned long*)&ul1);
if( ret == SOCKET_ERROR)
{
return false
}
devuelve verdadero;
}
bool CHttpDownload::GetResponseHeader()
{
char c = 0;
bool bEndResponse = false;
int nIndex = 0;
int ret;
while(!bEndResponse && nIndex < 1024)
{
ret = SelectRecv(&m_szResponseHeader[nIndex++], 1
if (ret <= 0);
devuelve falso;
if(nIndex >= 4)
{
if(m_szResponseHeader[nIndex - 4] == ' \r' && m_szResponseHeader [nIndex - 3] == '\n'
&& m_szResponseHeader[nIndex - 2] == '\r' && m_szResponseHeader[nIndex - 1] == '\n')
bEndResponse = true;
}
}
m_nResponseHeaderSize = nIndex;
devuelve verdadero; p>
}
int CHttpDownload::GetServerInfo(DWORD &dwContentLength, DWORD &dwStatusCode) const
{
if (0 == m_nResponseHeaderSize) p>
{
dwContentLength = -1
dwStatusCode = -1;
devuelve -1;
}
char szState[3];
szState[0] = m_szResponseHeader[9];
szState[1] = m_szResponseHeader[10];
szState[ 2] = m_s
zResponseHeader[11];
dwStatusCode = (DWORD)_ttol(szState);
// Obtener longitud del contenido
CString strResponseHeader = m_szResponseHeader;
int nPos = strResponseHeader.Find("Content-length:");
if (nPos == -1)
return -1;
CString strDownFileLen = strResponseHeader.Mid(nPos + strlen("Content-length:"));
nPos = strDownFileLen.Find("\r\n");
if ( nPos == -1)
return -1;
strDownFileLen = strDownFileLen.Left(nPos);
strDownFileLen.TrimLeft();
strDownFileLen.TrimRight();
// Longitud del contenido:
dwContentLength = (DWORD) _ttol( (LPCTSTR)strDownFileLen );
return 0;
}
int CHttpDownload::SelectSend(char *pData, int len, long timeout /* = DEFAULT_RECVTIMEOUT */)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(m_hSocket, &writefds);
timeval tv = { timeout, 0 }; /p>
int ret = select(0, NULL, &writefds, NULL, &tv);
if (ret == 0 || ret == SOCKET_ERROR)
{
devuelve 0;
}
if (FD_ISSET(m_hSocket, &writefds) == 0)
devuelve 0;
ret = enviar(m_hSocket, pData, len, 0);
if (ret == SOCKET_ERROR)
{
// DWORD dwError = WSAGetLastError();
devuelve 0;
}
si no (ret == 0)
{
devolver 0;
}
devolver ret;
}
int CHttpDownload::SelectRecv(char *pData, int len, tiempo de espera largo)
{
fd_set
readfds;
FD_ZERO(&readfds);
FD_SET(m_hSocket, &readfds);
timeval tv = { timeout, 0 }; > int ret = select(0, &readfds, NULL, NULL, &tv);
if (ret == 0 || ret == SOCKET_ERROR)
{
devuelve 0;
}
si (FD_ISSET(m_hSocket, &readfds) == 0)
devuelve 0;
ret = recv(m_hSocket, pData, len, 0);
if (ret == SOCKET_ERROR)
{
// DWORD dwError = WSAGetLastError();
devuelve 0;
}
si no (ret == 0)
{
devuelve 0 ;
}
devolver ret;
}
/*************** *** ************************************************* **** *******
Descargar archivos de registro de alarmas de eventos históricos
http://172.16.0.108/histevent.xml
* ************************************************* ***** *******************/
bool CHttpDownload::Download(LPCTSTR lpszDownloadUrl, LPCTSTR lpszSavePath)
{
int nPort;
CString strService, strObject;
if (!ParseURL(lpszDownloadUrl, strService, strObject, nPort))
{
devuelve falso;
}
if (!CreateSocket())
devuelve falso;
if (!Connect( strService, nPort))
devuelve falso;
FormatRequestHeader(strService, nPort, strObject);
if (!SendRequest( ))
return false;
DWORD dwFileLen, dwStatuCode;
if (-1 == GetServerInfo(dwFileLen, dwStatuCode))
{
>
return false;
}
CFile filedown;
if (!filedown.Open(lpszSavePath, CFile::modeCreate|CFile::modeWrite ))
{
return false;
}
DWORD dwTotalBytes = 0;
char szdata[ 2048] = { 0 };
while (dwTotalBytes < dwFileLen)
{
int nRecvBytes = SelectRecv(szdata, 2048
<); p> if (nRecvBytes <= 0 ){
break;
}
filedown.Write(szdata, nRecvBytes);
dwTotalBytes += nRecvBytes;
}
CloseSocket();
filedown.Close();
if (dwTotalBytes < dwFileLen)
{
intentar
{
CFile::Remove(lpszSavePath);
}
captura (CFileException* e)
{
e->Delete();
}
devuelve falso;
}
devuelve verdadero;
}