【问题标题】:Write the Indy 10 of Delphi Codes's to C ++ Builder's Indy 10将 Delphi Codes 的 Indy 10 写入 C++ Builder 的 Indy 10
【发布时间】:2015-09-14 13:44:19
【问题描述】:

我是学习 C++ Builder 的新手。三天前,我安装了 Embarcadero®。 C++Builder® 2010。这门语言对我来说很有趣。

在 Delphi 中,我通常使用 Indy 9 和 10 的 TIdMappedPortTCP 编写一个简单的代理服务器。我通常使用它的 OnExecute 和 OnOutboundData 事件来修改通过代理的数据。

由于我是 C++ Builder 的新手,所以我不知道如何将我的 Delphi 代码转换为完全正确的 C++ Builder 代码。

我尝试了很多方法,包括阅读几本书,其中一本是 Herbert SchildtBorland C ++ Builder - The Complete Reference,如以及增加知识。不幸的是,书中根本没有讨论与我的病情有关的非常重要的事情。另外,我在谷歌上找到了参考资料,但我没有找到。

所以,我冒昧地寻求您的帮助。我真的需要它。 请帮忙!非常感谢。

以下是我要写入 C++ Builder 的 Indy 10 的 Delphi 代码。

......

procedure TForm.IdMappedPortTCP1Execute(AContext: TIdContext);
var
Mydata, NetData: string;
begin
  if (Pos('HTTP',netstring(AContext)) <> 0) or (Pos('GET',netstring(AContext)) <> 0) then begin
   NetData := netstring(AContext);
   TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(AddHeader(netstring(AContext),'Connection: Keep-Alive'));
     Sleep(1000);
     Mydata  := 'GET http://website.com/ HTTP/1.1'+#13#10+'Host: website.com'#13#10;
     NetData := Mydata + Netdata;
   TIdMappedPortContext(AContext).NetData := netbyte(Netdata);
   TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(netbyte(Mydata + NetData));
  end;
end;

......

【问题讨论】:

  • 也许这不是学习一门新语言的方法。
  • 恕我直言,这是正确的方法之一,大卫爵士!...
  • 我先从语言基础开始
  • 请停止更改问题。请停止在答案中提出新问题。问题进入问题。如果你有一个新的,问一个新的。
  • 阅读 Schildt 并不是学习任何东西的正确方式

标签: delphi c++builder indy indy10 indy-9


【解决方案1】:

literal 到 C++Builder 的翻译如下所示:

......

String __fastcall AddHeader(String S, String Header)
{
    S = StringReplace(S, "\r\n\r\n", "\r\n" + Header + "\r\n\r\n", TReplaceFlags() << rfReplaceAll);
    return S;
}

void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
    String Mydata, NetData;

    if ((netstring(AContext).Pos("HTTP") != 0) || (netstring(AContext).Pos("GET") != 0))
    {
        NetData = netstring(AContext);
        TIdMappedPortContext(AContext)->OutboundClient->IOHandler->Write(AddHeader(netstring(AContext), "Connection: Keep-Alive"));
        Sleep(1000);
        Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n";
        NetData = Mydata + Netdata;
        static_cast<TIdMappedPortContext*>(AContext)->NetData = netbyte(Netdata);
        static_cast<TIdMappedPortContext*>(AContext)->OutboundClient->IOHandler->Write(netbyte(Mydata + NetData));
    }
}

......

这是一个稍微精简的版本:

......

String __fastcall AddHeader(String S, String Header)
{
    return StringReplace(S, "\r\n\r\n", "\r\n" + Header + "\r\n\r\n", TReplaceFlags() << rfReplaceAll);
}

void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
    String NetData = netstring(AContext);
    if ((NetData.Pos("HTTP") != 0) || (NetData.Pos("GET") != 0))
    {
        Sleep(1000);
        String Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n" + AddHeader(NetData, "Connection: Keep-Alive");
        static_cast<TIdMappedPortContext*>(AContext)->NetData = netbyte(Mydata);
    }
}

......

但无论哪种方式,这绝对不是在 Indy 中实现可行 HTTP 代理的可靠方式。事实上,Indy 10 正是为此目的引入了一个特定的TIdHTTPProxyServer 组件。您应该认真考虑使用它而不是 TIdMappedPortTCP。例如,上面可以在TIdHTTPProxyServer 中这样完成:

class TIdHTTPProxyServerContextAccess : public TIdHTTPProxyServerContext
{
public:
    void SetCommand(String Value) { FCommand = Value; }
    void SetDocument(String Value) { FDocument = Value; }
    void SetTarget(String Value) { FTarget = Value; }
};

void __fastcall TForm1.IdHTTPProxyServer1HTTPBeforeCommand(TIdHTTPProxyServerContext *AContext)
{
    static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetCommand("GET");
    static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetTarget ("http://website.com/");
    static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetDocument("/");

    AContext->Headers->Values["Host"] = "website.com";
    AContext->Headers->Values["Connection"] = "Keep-Alive";

    /*
    the original code was not changing the Host/Port where the
    HTTP request was being sent to.  But if you needed to,
    you can do it like this... 

    static_cast<TIdTCPClient*>(AContext->OutboundClient)->Host = "website.com";
    static_cast<TIdTCPClient*>(AContext->OutboundClient)->Port = 80;
    */
}

更新:您链接到的 netstring()netbyte() 函数存在语法错误,并且有不必要的开销(无需涉及 MIME 只是将字符串转换为字节数组和反之亦然,Indy 具有专门用于此目的的功能)。以下是修正后的版本:

String __fastcall netstring(TIdMappedPortContext* AContext)
{
    return BytesToStringRaw(AContext->NetData);
}

TIdBytes __fastcall netbyte(String S)
{
    return ToBytes(S, IndyTextEncoding_8Bit());
}

因此,您实际上可以完全消除这些功能:

void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
    TIdMappedPortContext *ctx = static_cast<TIdMappedPortContext*>(AContext)
    String NetData = BytesToStringRaw(ctx->NetData);
    if ((NetData.Pos("HTTP") != 0) || (NetData.Pos("GET") != 0))
    {
        Sleep(1000);
        String Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n" + AddHeader(NetData, "Connection: Keep-Alive");
        ctx->NetData = ToBytes(Mydata);
    }
}

【讨论】:

  • 非常感谢。你的回答对我帮助很大。顺便说一句,我仍然收到错误 [BCC32 Error] Unit1.cpp(116): E2303 Type name expected 与调用 netstring + netbyte 函数有关,你可以看到函数here。您可以查看我的整个 UNIT.CPP 和 UNIT.H 代码here。你能再帮我解决这个问题吗?
  • 谢谢你,雷米先生。但是,我仍然遇到两个错误:[BCC32 Error] Unit1.cpp(111): E2268 Call to undefined function 'BytesToStringRaw'[BCC32 Error] Unit1.cpp(118): E2268 Call to undefined function 'IndyTextEncoding_8Bit'。仅供参考,我已将 #pragma link "IdGlobal"#pragma link "IdGlobalProtocols" 放入我的 unit1.cpp,还将 #include "IdGlobal.hpp"#include "IdGlobalProtocols.hpp" 放入 unit1.h,但这些错误仍然发生。那么,我应该使用哪些 Indy 10 组件?
  • 好的,我得到了IndyTextEncoding_8BitBytesToStringRaw在最新Indy 10的IdGlobal.pas文件中定义的信息。我会尝试更新我的Indy 10。非常感谢.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多