283 lines
10 KiB
C++
283 lines
10 KiB
C++
|
|
// TestEcho-SSL-Console Client
|
|||
|
|
// 基于HP-Socket的SSL客户端控制台程序
|
|||
|
|
|
|||
|
|
#include "pch.h"
|
|||
|
|
|
|||
|
|
// SSL证书配置(来自helper.cpp)
|
|||
|
|
static const char* g_c_lpszPemCert = R"(-----BEGIN CERTIFICATE-----
|
|||
|
|
MIIDszCCApugAwIBAgIBATANBgkqhkiG9w0BAQsFADB7MQswCQYDVQQGEwJDTjEL
|
|||
|
|
MAkGA1UECAwCR0QxCzAJBgNVBAcMAkdaMQwwCgYDVQQKDANTU1QxDzANBgNVBAsM
|
|||
|
|
Bkplc3NtYTETMBEGA1UEAwwKamVzc21hLm9yZzEeMBwGCSqGSIb3DQEJARYPbGRj
|
|||
|
|
c2FhQDIxY24uY29tMCAXDTI0MDYyNjA1MjUwOFoYDzIyNDMwNzA5MDUyNTA4WjBu
|
|||
|
|
MQswCQYDVQQGEwJDTjELMAkGA1UECAwCR0QxDDAKBgNVBAoMA1NTVDEPMA0GA1UE
|
|||
|
|
CwwGSmVzc21hMRMwEQYDVQQDDApqZXNzbWEub3JnMR4wHAYJKoZIhvcNAQkBFg9s
|
|||
|
|
ZGNzYWFAMjFjbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCD
|
|||
|
|
+MyrJEKCheRoOpMRjR78S8hr9W7XN0/EZWyVKwXRT7EE0aGiQdH/W2a+qpWRMa6E
|
|||
|
|
Qi47zdBnt0P8ZoFiItQhuhwUJ064afpVoaHHX25UdbF8r+sRTofadughETBBj2Cf
|
|||
|
|
qh0ia6EOB0QvpJpywWmGZPoMtypjbUiTb/YGOJh2qsVr67MN/E48vt7qt0VxF9SE
|
|||
|
|
pucvqhraTBljWCeRVCae2c0yBSpq/n+7NhamK7+g3xxCKWRz4pN3wrIoEsXTboTh
|
|||
|
|
z940caDgthCc23VJ080DN44jZg6c87huKIuxbebJqw2HCM4DwrW+OSzTLszpFAXZ
|
|||
|
|
yarllOzWnBut20zmYnl1AgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFJ5E
|
|||
|
|
RJmJ4pUzEbcU9Yge6nr0oi51MB8GA1UdIwQYMBaAFN49z48DywmoD4cNTQgC6nn2
|
|||
|
|
QJoUMA0GCSqGSIb3DQEBCwUAA4IBAQBpoSFfDDDKMAy95tSROpYu5WSWQXe6B7kl
|
|||
|
|
PGJAF6mWe/4b7jHQqDUVkEmFmbMWUAtpTC3P01TrV77dhIosAnC/B76fb7Pto8W4
|
|||
|
|
cjGpWAT0sSegZuhnLtguTGlnR0vVSh/yRRDEtjN8loWpu3BLWVHYOKnn62QGfY0B
|
|||
|
|
sRGrfZsKvwB+1w+HOvGopnWv6UYwrzEKthjPMR65rOsoManOv24ua8baJmq0gqF9
|
|||
|
|
752kD8n703uWUBx79/QlNIPMZC1iUIi1mEjyrTgSag6+3sWAIKihaoF/Nf9d01nw
|
|||
|
|
iL16EIT5dJ0QJWDCeIxhuTZckw+gL1pBeQU7pqzKHPnvo+8GBnTG
|
|||
|
|
-----END CERTIFICATE-----
|
|||
|
|
)";
|
|||
|
|
|
|||
|
|
static const char* g_c_lpszPemKey = R"(-----BEGIN ENCRYPTED PRIVATE KEY-----
|
|||
|
|
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
|
|||
|
|
-----END ENCRYPTED PRIVATE KEY-----
|
|||
|
|
)";
|
|||
|
|
|
|||
|
|
static const char* g_c_lpszCAPemCert = R"(-----BEGIN CERTIFICATE-----
|
|||
|
|
MIID2TCCAsGgAwIBAgIUM8TTtPU+ejzffYXCcs/zZsU7OuIwDQYJKoZIhvcNAQEL
|
|||
|
|
BQAwezELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQHDAJHWjEMMAoG
|
|||
|
|
A1UECgwDU1NUMQ8wDQYDVQQLDAZKZXNzbWExEzARBgNVBAMMCmplc3NtYS5vcmcx
|
|||
|
|
HjAcBgkqhkiG9w0BCQEWD2xkY3NhYUAyMWNuLmNvbTAgFw0yNDA2MjYwNTA0NDNa
|
|||
|
|
GA8yMjcwMTEyNDA1MDQ0M1owezELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQsw
|
|||
|
|
CQYDVQQHDAJHWjEMMAoGA1UECgwDU1NUMQ8wDQYDVQQLDAZKZXNzbWExEzARBgNV
|
|||
|
|
BAMMCmplc3NtYS5vcmcxHjAcBgkqhkiG9w0BCQEWD2xkY3NhYUAyMWNuLmNvbTCC
|
|||
|
|
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAML+v79+aLQt0Za0dTIZHI5B
|
|||
|
|
NDs0g5G8bhdOTlW/kNWflaziZ3GY6d6nJSkQ5e29kyFKxlOD6Gls6bOJ86U71u4R
|
|||
|
|
bCmoFvRTDH4q2cJ/+PbiioLpNveDG6lnRCs9JNRQoJrkpRo6urnVnAdsIf6UFjLI
|
|||
|
|
dlByNMPGYJ0V8/oKJG5Vu5gcbZV0jVA5+tswkH/zquexEXoKvp18mcwl+pNc/LwW
|
|||
|
|
0WnGj0uoJjxHg4GsS78PASjhxMR/2d/1OpgPauldFaNHjVPtaLqJnuejwA6M6Sz8
|
|||
|
|
iFPybAQAMpHL9W8kf08jtbnFvnm4ibUkQL5h+OJoIEQa9AVZOSoFG2/g5Zcn8X8C
|
|||
|
|
AwEAAaNTMFEwHQYDVR0OBBYEFN49z48DywmoD4cNTQgC6nn2QJoUMB8GA1UdIwQY
|
|||
|
|
MBaAFN49z48DywmoD4cNTQgC6nn2QJoUMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
|
|||
|
|
hvcNAQELBQADggEBALJnYrYBSZLyYX14FQ04zxG3AX0CtQzNOOa7LDrr+H8Ly+nK
|
|||
|
|
qS87gg2njMVZH1zM2demtMwydR/F2Ui8ggaduMvc9h5YgQKEwYl8KarJEY03oZoe
|
|||
|
|
zbQGBxCXpDOtMs1vujzcl/iZbSzwEDF3g4la5U8q4MlmfGFKz9CJbvoxecqYA206
|
|||
|
|
nNbW2XZsW/xMiQv6iAw5iP/LOR9HAyxcvXIsL790nfcgnTYLmyP254Dj4outc6R+
|
|||
|
|
PA+f/c1FvkbUBTR5vJt2tsvHcNU218rY2hyOIhDmZeUWprqBO19sUk3scLbVPr3+
|
|||
|
|
WEWEl2XaCekKuPtAnMgVQuFsocXGyiuIhkOe5Z4=
|
|||
|
|
-----END CERTIFICATE-----
|
|||
|
|
)";
|
|||
|
|
|
|||
|
|
static const int g_c_iVerifyMode = SSL_VM_PEER;
|
|||
|
|
static const char* g_c_lpszKeyPassword = "123456";
|
|||
|
|
static const LPCTSTR DEFAULT_ADDRESS = _T("127.0.0.1");
|
|||
|
|
static const USHORT DEFAULT_PORT = 5555;
|
|||
|
|
|
|||
|
|
inline static bool writeFile(const std::string& path, const std::vector<unsigned char>& data) {
|
|||
|
|
std::ofstream f(path, std::ios::binary);
|
|||
|
|
if (!f) return false;
|
|||
|
|
// 写入数据
|
|||
|
|
f.write(reinterpret_cast<const char*>(data.data()), data.size());
|
|||
|
|
// 检查是否全部写入成功
|
|||
|
|
if (!f) return false;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
// 客户端监听器类
|
|||
|
|
class CClientListener : public CTcpClientListener
|
|||
|
|
{
|
|||
|
|
private:
|
|||
|
|
bool m_bConnected;
|
|||
|
|
|
|||
|
|
public:
|
|||
|
|
CClientListener() : m_bConnected(false) {}
|
|||
|
|
|
|||
|
|
bool IsConnected() const { return m_bConnected; }
|
|||
|
|
|
|||
|
|
virtual EnHandleResult OnConnect(ITcpClient* pSender, CONNID dwConnID) override
|
|||
|
|
{
|
|||
|
|
TCHAR szAddress[100];
|
|||
|
|
int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);
|
|||
|
|
USHORT usPort;
|
|||
|
|
pSender->GetLocalAddress(szAddress, iAddressLen, usPort);
|
|||
|
|
|
|||
|
|
std::wcout << L"[客户端] 连接成功: 本地地址=" << szAddress << L":" << usPort << std::endl;
|
|||
|
|
m_bConnected = true;
|
|||
|
|
|
|||
|
|
return HR_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
virtual EnHandleResult OnHandShake(ITcpClient* pSender, CONNID dwConnID) override
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] SSL握手完成" << std::endl;
|
|||
|
|
return HR_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override
|
|||
|
|
{
|
|||
|
|
std::string strData((char*)pData, iLength);
|
|||
|
|
std::cout << "[客户端] 收到服务器数据,长度为:" << iLength << std::endl;
|
|||
|
|
|
|||
|
|
return HR_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
virtual EnHandleResult OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override
|
|||
|
|
{
|
|||
|
|
return HR_OK;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
virtual EnHandleResult OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) override
|
|||
|
|
{
|
|||
|
|
if (iErrorCode == SE_OK)
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] 连接已关闭" << std::endl;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] 连接错误: 错误码=" << iErrorCode << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_bConnected = false;
|
|||
|
|
return HR_OK;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
void PrintMenu()
|
|||
|
|
{
|
|||
|
|
std::wcout << L"\n----------------------------------------" << std::endl;
|
|||
|
|
std::wcout << L"命令菜单:" << std::endl;
|
|||
|
|
std::wcout << L" 1 - 发送 'hello' 到服务器" << std::endl;
|
|||
|
|
std::wcout << L" Q - 断开连接并退出" << std::endl;
|
|||
|
|
std::wcout << L"----------------------------------------" << std::endl;
|
|||
|
|
std::wcout << L"请输入命令: ";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int main()
|
|||
|
|
{
|
|||
|
|
// 设置控制台UTF-8编码和locale
|
|||
|
|
SetConsoleOutputCP(CP_UTF8);
|
|||
|
|
std::locale::global(std::locale(""));
|
|||
|
|
std::wcout.imbue(std::locale(""));
|
|||
|
|
|
|||
|
|
std::wcout << L"========================================" << std::endl;
|
|||
|
|
std::wcout << L" HP-Socket SSL Client 控制台演示程序" << std::endl;
|
|||
|
|
std::wcout << L"========================================" << std::endl;
|
|||
|
|
std::wcout << std::endl;
|
|||
|
|
|
|||
|
|
// 创建监听器和客户端
|
|||
|
|
CClientListener listener;
|
|||
|
|
CSSLClientPtr client(&listener);
|
|||
|
|
|
|||
|
|
// 初始化SSL上下文
|
|||
|
|
std::wcout << L"[客户端] 正在初始化SSL环境..." << std::endl;
|
|||
|
|
if (!client->SetupSSLContextByMemory(g_c_iVerifyMode, g_c_lpszPemCert, g_c_lpszPemKey,
|
|||
|
|
g_c_lpszKeyPassword, g_c_lpszCAPemCert))
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] SSL初始化失败!错误码: " << client->GetLastError() << std::endl;
|
|||
|
|
std::wcout << L"按任意键退出..." << std::endl;
|
|||
|
|
_getch();
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
std::wcout << L"[客户端] SSL环境初始化成功" << std::endl;
|
|||
|
|
|
|||
|
|
// 连接服务器
|
|||
|
|
std::wcout << L"[客户端] 正在连接服务器 " << DEFAULT_ADDRESS << L":" << DEFAULT_PORT << L" ..." << std::endl;
|
|||
|
|
if (!client->Start(DEFAULT_ADDRESS, DEFAULT_PORT, FALSE))
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] 连接失败!错误码: " << client->GetLastError() << std::endl;
|
|||
|
|
std::wcout << L"按任意键退出..." << std::endl;
|
|||
|
|
_getch();
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 等待连接完成
|
|||
|
|
int waitCount = 0;
|
|||
|
|
while (!listener.IsConnected() && waitCount < 50)
|
|||
|
|
{
|
|||
|
|
Sleep(100);
|
|||
|
|
waitCount++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!listener.IsConnected())
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] 连接超时!" << std::endl;
|
|||
|
|
client->Stop();
|
|||
|
|
client->CleanupSSLContext();
|
|||
|
|
std::wcout << L"按任意键退出..." << std::endl;
|
|||
|
|
_getch();
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::wcout << L"[客户端] 已连接到服务器,可以开始发送消息" << std::endl;
|
|||
|
|
|
|||
|
|
// 主循环 - 等待用户输入命令
|
|||
|
|
PrintMenu();
|
|||
|
|
|
|||
|
|
bool bRunning = true;
|
|||
|
|
while (bRunning)
|
|||
|
|
{
|
|||
|
|
if (_kbhit())
|
|||
|
|
{
|
|||
|
|
char ch = _getch();
|
|||
|
|
std::cout << ch << std::endl;
|
|||
|
|
|
|||
|
|
if (ch == '1')
|
|||
|
|
{
|
|||
|
|
// 发送 "hello" 到服务器
|
|||
|
|
std::string message = "hello";
|
|||
|
|
if (client->Send((const BYTE*)message.c_str(), (int)message.length()))
|
|||
|
|
{
|
|||
|
|
std::cout << "[客户端] 发送消息: \"" << message << "\"" << std::endl;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] 发送失败!错误码: " << client->GetLastError() << std::endl;
|
|||
|
|
}
|
|||
|
|
PrintMenu();
|
|||
|
|
}
|
|||
|
|
else if (ch == 'q' || ch == 'Q')
|
|||
|
|
{
|
|||
|
|
bRunning = false;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
std::wcout << L"无效命令,请重新输入。" << std::endl;
|
|||
|
|
PrintMenu();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Sleep(100);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 断开连接
|
|||
|
|
std::wcout << L"[客户端] 正在断开连接..." << std::endl;
|
|||
|
|
if (client->Stop())
|
|||
|
|
{
|
|||
|
|
std::wcout << L"[客户端] 已断开连接" << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清理SSL上下文
|
|||
|
|
client->CleanupSSLContext();
|
|||
|
|
|
|||
|
|
std::wcout << L"按任意键退出..." << std::endl;
|
|||
|
|
_getch();
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|