- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试构建通过 Indy SSL TCP 组件 (C++ Builder 2010) 进行通信的服务器和客户端应用程序。我使用以下命令生成了证书和私钥:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -config C:\openssl.cnf
服务器代码:
#include <vcl.h>
#pragma hdrstop
#include <tchar.h>
//---------------------------------------------------------------------------
#pragma argsused
#include <idglobal.hpp>
#include <IdTcpServer.hpp>
#include <IdSSLOpenSSL.hpp>
#include <vector>
#include <string>
#include <memory>
#include <iostream>
#include <windows.h>
#include "comm.h"
#pragma link "IndyCore140.lib"
#pragma link "IndyProtocols140.lib"
#pragma link "IndySystem140.lib"
/////////////////////////////////////////////////////////////////////////////
// Server
/////////////////////////////////////////////////////////////////////////////
class TServer
{
public:
TServer(int Port, const std::string& cert, const std::string& key,
const std::string& password )
: FPassword(password),
FServer(new TIdTCPServer(NULL))
{
FServer->OnConnect = ServerOnConnect;
FServer->OnExecute = ServerOnExecute;
FServer->DefaultPort = Port;
TIdServerIOHandlerSSLOpenSSL* ioHandler =
new TIdServerIOHandlerSSLOpenSSL(NULL);
ioHandler->OnGetPassword = SetPassword;
ioHandler->OnVerifyPeer = VerifyPeer;
ioHandler->SSLOptions->Mode = sslmServer;
ioHandler->SSLOptions->VerifyDepth = 0;
ioHandler->SSLOptions->CertFile = cert.c_str();
ioHandler->SSLOptions->KeyFile = key.c_str();
ioHandler->SSLOptions->SSLVersions << sslvSSLv23;
ioHandler->SSLOptions->VerifyMode.Clear();
FServer->IOHandler = ioHandler;
}
~TServer()
{
}
public:
void Start()
{
FServer->Active = true;
std::cout << "Listening on port " << FServer->DefaultPort << std::endl;
}
void Stop()
{
FServer->Active = false;
}
private:
void __fastcall ServerOnExecute(TIdContext* ctx)
{
TIdTCPConnection* conn = ctx->Connection;
try
{
std::string command = Recv(conn);
std::cout << command << std::endl;
if( strnicmp(command.c_str(), "HELLO", 5) == 0 ) // Start session
{
Send(conn, "HELLO");
}
}
catch(Exception& e)
{
std::cout << AnsiString(e.Message).c_str() << std::endl;
}
conn->Disconnect();
}
void __fastcall ServerOnConnect(TIdContext* context)
{
std::cout << "Client connected" << std::endl;
}
bool __fastcall VerifyPeer(TIdX509* Certificate, bool AOk, int ADepth)
{
return AOk;
}
void __fastcall SetPassword(AnsiString& Password)
{
Password = FPassword.c_str();
}
private:
std::auto_ptr<TIdTCPServer> FServer;
const std::string FPassword;
};
///
// Press Ctrl+C to close application
///
HANDLE hExitEvent = NULL;
BOOL CtrlHandler( DWORD ctl )
{
if( ctl == CTRL_C_EVENT)
{
if( hExitEvent != NULL )
{
std::cout << "Closing application..." << std::endl;
SetEvent(hExitEvent);
}
return TRUE;
}
return FALSE;
}
///
int _tmain(int argc, _TCHAR* argv[])
{
std::auto_ptr<TServer> server(new TServer(50136,
"c:\\cert.pem",
"c:\\key.pem",
"MyPassword"));
hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if( SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) )
{
try
{
server->Start();
WaitForSingleObject(hExitEvent, INFINITE);
server->Stop();
Sleep(1000);
}
catch(Exception& e)
{
std::cout << AnsiString(e.Message).c_str() << std::endl;
}
}
CloseHandle(hExitEvent);
return 0;
}
客户端代码:
#include <vcl.h>
#pragma hdrstop
#include <idglobal.hpp>
#include <IdTCPClient.hpp>
#include <IdSSLOpenSSL.hpp>
#include <vector>
#include <string>
#include <memory>
#include <iostream>
#include <tchar.h>
#include "comm.h"
//---------------------------------------------------------------------------
#pragma argsused
#pragma link "IndyCore140.lib"
#pragma link "IndyProtocols140.lib"
#pragma link "IndySystem140.lib"
void TestConnection()
{
std::auto_ptr<TIdTCPClient> client(new TIdTCPClient(NULL));
try
{
client->Host = "192.168.1.3";
client->Port = 50136;
client->ConnectTimeout = 10000;
client->ReadTimeout = 10000;
// SSL
TIdSSLIOHandlerSocketOpenSSL* ioHandler = new TIdSSLIOHandlerSocketOpenSSL(NULL);
ioHandler->SSLOptions->Mode = sslmClient;
ioHandler->SSLOptions->VerifyDepth = 0;
// ioHandler->SSLOptions->CertFile = "c:\\cert.pem";
ioHandler->SSLOptions->SSLVersions << sslvSSLv23;
// ioHandler->SSLOptions->VerifyMode.Clear();
client->IOHandler = ioHandler;
client->Connect();
///
// Test session start
///
Send(client.get(), "HELLO");
std::string response = Recv(client.get());
std::cout << response << std::endl;
}
catch(Exception& e)
{
std::cout << AnsiString(e.Message).c_str() << std::endl;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
TestConnection();
return 0;
}
comm.h
#ifndef COMM_H
#define COMM_H
#include <idglobal.hpp>
#include <IdTcpServer.hpp>
#include <IdSSLOpenSSL.hpp>
#include <vector>
#include <string>
//---------------------------------------------------------------------------
typedef std::vector<unsigned char> TBuffer;
void SendByteArray(TIdTCPConnection* Connection,
const TBuffer& array)
{
TIdBytes src;
src = Idglobal::RawToBytes(&array[0], array.size());
Connection->IOHandler->Write(src);
}
//---------------------------------------------------------------------------
void ReceiveByteArray(TIdTCPConnection* Connection,
TBuffer& array, unsigned int size)
{
TIdBytes dest;
Connection->IOHandler->ReadBytes(dest, size);
array.resize(size);
Idglobal::BytesToRaw(dest, &array[0], size);
}
void Send(TIdTCPConnection* Connection, const std::string& cmd)
{
TBuffer buffer(cmd.begin(), cmd.end());
SendByteArray(Connection, buffer);
}
std::string Recv(TIdTCPConnection* Connection)
{
TBuffer buffer;
ReceiveByteArray(Connection, buffer, 5);
std::string cmd(buffer.begin(), buffer.end());
return cmd;
}
#endif //COMM_H
服务器启动没有任何错误。当我尝试连接到服务器时,客户端抛出异常
Project sslclient.exe raised exception class EIdOSSLConnectError with message 'Error connecting with SSL.
EOF was observed that violates the protocol'.
并且服务器进入无限循环,并在每次迭代时出现异常 Connection Closed.
。我使用 OpenSSL 库 v.1.0.1.3 在 Windows 7 上运行测试。请帮助让它发挥作用。
最佳答案
客户端错误是因为当TIdServerIOHandlerSSLOpenSSL
接受一个新的客户端连接,PassThrough
客户端 IOHandler 的属性默认设置为 true,因此 SSL/TLS 尚未激活。这允许服务器在每个连接的基础上动态决定是否激活 SSL/TLS。例如,如果您的服务器正在监听多个端口并且仅在某些端口上使用 SSL。或者,如果您的协议(protocol)实现了 STARTTLS
样式命令。所以你需要设置 PassThrough
当您准备好接受 SSL/TLS 握手时属性设置为 false,例如:
void __fastcall ServerOnConnect(TIdContext* context)
{
std::cout << "Client connected" << std::endl;
static_cast<TIdSSLIOHandlerSocketOpenSSL*>(context->Connection->IOHandler)->PassThrough = false;
}
在客户端,设置PassThrough
当您准备好启动 SSL/TLS 握手时设置为 false:
ioHandler->PassThrough = false;
如果PassThrough
Connect()
时为假被调用时,一旦套接字成功连接到服务器,握手将立即执行。
话虽如此,Indy 依赖于异常,所以你不应该使用 try/catch
block 在 OnExecute
事件处理程序。您可以使用 OnException
记录未捕获异常的事件,例如:
void __fastcall ServerOnExecute(TIdContext* ctx)
{
TIdTCPConnection* conn = ctx->Connection;
std::string command = Recv(conn);
std::cout << command << std::endl;
if( strnicmp(command.c_str(), "HELLO", 5) == 0 ) // Start session
{
Send(conn, "HELLO");
}
conn->Disconnect();
}
void __fastcall ServerOnException(TIdContext* ctx, Exception *excpt)
{
std::cout << AnsiString(excpt->Message).c_str() << std::endl;
}
但是,如果您必须使用 try/catch
然后一定要重新抛出任何 EIdException
基于你捕获的异常。让TIdTCPServer
处理它们,例如:
void __fastcall ServerOnExecute(TIdContext* ctx)
{
TIdTCPConnection* conn = ctx->Connection;
try
{
std::string command = Recv(conn);
std::cout << command << std::endl;
if( strnicmp(command.c_str(), "HELLO", 5) == 0 ) // Start session
{
Send(conn, "HELLO");
}
}
catch(const Exception& e)
{
std::cout << AnsiString(e.Message).c_str() << std::endl;
if (dynamic_cast<const EIdException*>(&e))
throw;
}
conn->Disconnect();
}
或者:
void __fastcall ServerOnExecute(TIdContext* ctx)
{
TIdTCPConnection* conn = ctx->Connection;
try
{
std::string command = Recv(conn);
std::cout << command << std::endl;
if( strnicmp(command.c_str(), "HELLO", 5) == 0 ) // Start session
{
Send(conn, "HELLO");
}
}
catch(const EIdException&)
{
throw;
}
catch(const Exception& e)
{
std::cout << AnsiString(e.Message).c_str() << std::endl;
}
conn->Disconnect();
}
此外,这些行也是错误的:
ioHandler->SSLOptions->SSLVersions << sslvSSLv23;
ioHandler->SSLOptions->VerifyMode.Clear();
您不能使用 <<
属性上的运算符,并调用 Clear()
是一个空操作。原因是因为这两行都在调用属性 getter,然后操作之后未分配回属性的临时对象。您必须手动执行此操作:
ioHandler->SSLOptions->SSLVersions = TIdSSLVersions() << sslvSSLv23;
ioHandler->SSLOptions->VerifyMode = TIdSSLVerifyModeSet();
最后:
#pragma link "IndyCore140.lib"
#pragma link "IndyProtocols140.lib"
#pragma link "IndySystem140.lib"
您不应该直接链接到 Indy 的 .lib 文件。您项目的 .bpr/.cproj 文件(而不是您的代码)应该包含对 Indy 运行时包的引用。
关于openssl - 无法连接到 Indy SSL TCP 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21768381/
我尝试使用SHA-256加密功能,但没有成功。 我需要获取字符串和文件的哈希值。我使用 Delphi 10.1 Berlin 和 Indy for Hash。 我的代码: uses System.Cl
是否有关于如何在 Lazarus 中安装 Indy 10 组件的分步指南? 我在 https://svn.atozed.com:444/svn/Indy10 查看了最后一个 snv 快照 用户名:In
我在 Delphi 7 中编写了一个程序(包括一个使用 Indy 的 ModBus 组件)。在我的机器上,它使用 Indy 9 并且工作正常。它通过 ModBus 协议(protocol)与其他机器进
我是 indy 新手,使用 CBuilder XE4 附带的任何版本。这是非常简单的代码,在我正在阅读的内容超过 16K 限制之前都可以正常工作...... String Ttcp_mgr::send
我在 4 个基于 ubuntu 的机器上设置了 4 个节点。我使用以下命令生成了这些节点所需的 key :init_indy_node VAL1 0.0.0.0 9701 0.0.0.0 9702 1
当前应用程序:Delphi 2006、indy9(大量使用 SOAP 和其他组件) 需要转到 Indy 10 以获得 TLS 支持(poodle 等)。 看着 http://www.indyproje
我是 C++ Builder 的新手。三天前,我安装了 Embarcadero®。 C++Builder® 2010。这门语言对我来说非常有趣。 在 Delphi 中,我通常使用 Indy 9 和 1
我对 SSL 和这些加密的东西完全陌生,但我需要让在移动设备上运行的客户端和服务器 Delphi XE6 应用程序进行通信。必须对 TCP 通信进行安全加密。 首先,我简单地编写了基于 Win32 客
我有三个问题: 是否可以通过多个连接破坏IdTCPServer? 我尝试测试我的应用程序,并且当我有多个连接时 - 它工作得很好(甚至几天),但是当有时连接数增加时,应用程序会导致访问冲突。我写的应用
我使用 Delphi XE 5/6,默认 Indy 版本,Windows 7。IdMappedPortTCP(放在表单上的组件)将本地流从 FFmpeg 重定向到 Twitch.tv,并且总是接近 2
我有一个客户端应用程序,它应该向可选的服务器应用程序发送通知消息。客户端不应受到服务器应用程序是否存在的影响。它应该尝试连接到服务器应用程序并发送通知消息,如果出现错误,它应该默默地忽略所有错误并继续
我在使用Indy(idTCPServer组件)读取客户端发送的数据时遇到一些问题,数据本身是十六进制格式的,所以我不能使用AThread.Connection.ReadLn( );为此... 这是我的
当Indy收到404时,我无法获取响应内容,它总是空的。 例如使用Indy访问https://www.etsy.com/people/car ,我收到 404 并且内容流(或分配的流)只是空的。对TH
很久以前,我使用 Delphi 2007 和 WebBroker (TWebModule) 启动了一些“Web 应用程序”。当时我假设您需要一个 Web 服务器(例如 Apache 或 Microso
这是我的程序: Application.FTP.Host:= vHost; Application.FTP.Port:= vPort; try Application.FTP.AutoLogin
以下代码请求 OAuth2 token 。它适用于 Indy 10.0.52,但对于 Indy 10 SVN 5412,由于请求凭据无效,它会生成 400 Bad Request 错误。 WXYZUs
我有一个应用程序需要从网络驱动器进行一些 FTP 上传。我为此使用 Indy。然后,当文件位于网络驱动器上并成功上传到 FTP 服务器时,我想通过电子邮件将同一文件发送给同事。 我正在使用下面的代码来
我正在使用 Indy UDP Server 读取一串数据。但是,我真的不知道如何使用 Adata 参数。我可以通过使用下面的 ByteToBin 函数将其转换为二进制,然后使用 BintoHex1 将
我是独立服务器的新手,所以我正在努力完成这个简单的任务。我必须创建一个服务器并上传一个小文件;它的大小始终为 128 字节。然后,当有人打开服务器主页时,文件会自动发送。所以: 在磁盘上上传一个文件(
我正在使用 Delphi 10.0 西雅图。 我想向 UDP 服务器发送请求,然后读取服务器响应,这是一个简单的字符串: Client side:send('12345') server side(o
我是一名优秀的程序员,十分优秀!