三、OpenSSL发送HTTPS请求
1.基本流程
HTTPS=HTTP + SSL,因此利用OpenSSL发送请求给HTTPS站点和第二章的SOCKET发送HTTP是非常相似的,只不过要在原生的套接字上套上SSL层,基本流程如下:
a. WSAStartup对Winsock服务进行初始化
b. 建立socket套接字
c. connect连接服务端
d. 建立SSL上下文
e. 建立SSL
f. 将SSL与前面建立的socket套接字绑定
g. SSL_write()发送数据
h. SSL_read()接收数据
下面以小米官网站点的登录为例,来展示利用OpenSSL如何访问HTTPS站点,模拟登陆,核心代码,见下一章节。
2.核心代码
#pragma comment( lib, libeay32.lib )
#pragma comment( lib, ssleay32.lib )
HttpsClient::HttpsClient(void):
wsaData(NULL),
socketAddrClient(NULL),
ssl(NULL),
sslCtx(NULL),
sslMethod(NULL),
serverCertification(NULL)
{
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
}
HttpsClient::~HttpsClient(void)
{
//!清理打开的句柄
if (NULL != ssl)
{
SSL_shutdown(ssl);
closesocket(socketClient);
SSL_free(ssl);
ssl = NULL;
}
if (NULL != sslCtx)
{
SSL_CTX_free(sslCtx);
}
WSACleanup();
}
BOOL HttpsClient::ConnectToServer(const CString strServerUrl, const int nPort)
{
cstrServerUrl = strServerUrl;
nServerPort = nPort;
BOOL bRet = FALSE;
do
{
if (!InitializeSocketContext())
{
break;
}
if (!SocketConnect())
{
break;
}
if (!InitializeSslContext())
{
break;
}
if (!SslConnect())
{
break;
}
bRet = TRUE;
} while (FALSE);
return bRet;
}
BOOL HttpsClient::LoginToServer(const CString strUsername, const CString strPasswd)
{
cstrUserName = strUsername;
cstrPassWord = strPasswd;
BOOL bRet = FALSE;
do
{
if (!SendLoginPostData())
{
break;
}
CString cstrRecvData;
RecvLoginPostData(cstrRecvData);
if (cstrRecvData.GetLength() == 0)
{
break;
}
ParseCookieFromRecvData(cstrRecvData);
if (cstrCookieUid.IsEmpty() || cstrCookieUid.Compare(EXPIRED) == 0)
{
break;
}
bRet = TRUE;
} while (FALSE);
return bRet;
}
BOOL HttpsClient::LogoutOfServer()
{
return FALSE;
}
BOOL HttpsClient::InitializeSocketContext()
{
//!初始化winSocket环境
BOOL bRet = FALSE;
wsaData = new WSADATA;
WORD wVersion = MAKEWORD(2, 2);
do
{
if(0 != WSAStartup(wVersion, wsaData))
{
break;
}
if(LOBYTE( wsaData->wVersion ) != 2 || HIBYTE( wsaData->wVersion ) != 2 )
{
WSACleanup();
break;
}
LPHOSTENT lpHostTent;
lpHostTent = gethostbyname(cstrServerUrl);
if (NULL == lpHostTent)
{
break;
}
socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketClient == INVALID_SOCKET)
{
WSACleanup();
break;
}
socketAddrClient = new SOCKADDR_IN;
socketAddrClient->sin_family = AF_INET;
socketAddrClient->sin_port = htons(nServerPort);
socketAddrClient->sin_addr = *((LPIN_ADDR)*lpHostTent->h_addr_list);
memset(socketAddrClient->sin_zero, 0, sizeof(socketAddrClient->sin_zero));
bRet = TRUE;
} while (FALSE);
return bRet;
}
BOOL HttpsClient::SocketConnect()
{
//!原生socket连接
BOOL bRet = FALSE;
do
{
if (SOCKET_ERROR == connect(socketClient, (LPSOCKADDR)socketAddrClient, sizeof(SOCKADDR_IN)))
{
int nErrorCode = WSAGetLastError();
closesocket(socketClient);