简体   繁体   English

使用TIdIOHandlerStream和TIdTCPClient读取数据流

[英]Reading stream of Data using TIdIOHandlerStream and TIdTCPClient

I have an app that needs to connect to a server using TCP/IP and then just wait for server to send data, and what ever server sends should be saved into a file. 我有一个需要使用TCP / IP连接到服务器的应用程序,然后仅等待服务器发送数据,并且服务器发送的内容都应保存到文件中。

Here is what I did: 这是我所做的:

The Header file 头文件

#ifndef MainH
#define MainH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>
#include <IdBaseComponent.hpp>
#include <IdComponent.hpp>
#include <IdIOHandler.hpp>
#include <IdIOHandlerStream.hpp>
#include <IdTCPClient.hpp>
#include <IdTCPConnection.hpp>
#include <boost/scoped_ptr.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    TIdTCPClient *pTCP;
    TIdIOHandlerStream *IdIOHandlerStream;
    TButton *Button1;
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall IdIOHandlerStreamGetStreams(TIdIOHandlerStream *ASender, TStream *&VReceiveStream, TStream *&VSendStream);
private:    // User declarations
    boost::scoped_ptr<TFileStream> mFile;
    boost::scoped_ptr<TMemoryStream> mMem;

    void __fastcall StopTcpClick(TObject* Sender);
public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

and the CPP file: 和CPP文件:

include <fmx.h>
#pragma hdrstop

#include "Main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner),
                            mFile(new TFileStream(L"C:\\IbsData.txt", fmCreate | fmOpenReadWrite | fmShareDenyWrite)),
                            mMem(new TMemoryStream())
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    pTCP->Connect();
    Button1->Text = L"Stop";
    Button1->OnClick = StopTcpClick;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::StopTcpClick(TObject* Sender)
{
    pTCP->Disconnect();
    Button1->Text = L"Start";
    Button1->OnClick = Button1Click;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdIOHandlerStreamGetStreams(TIdIOHandlerStream *ASender, TStream *&VReceiveStream, TStream *&VSendStream)
{
    VReceiveStream = mFile.get();
    VSendStream = mMem.get();
}

I have to note that IdIOHandlerStream has been set as the IOHandler of pTCP . 我必须注意, IdIOHandlerStream已设置为IOHandlerpTCP

The problem is, I know server is sending lots of data, but nothing gets written into the file. 问题是,我知道服务器正在发送大量数据,但是没有任何内容写入文件中。

Does anyone know why? 有人知道为什么吗?

You are using the wrong IOHandler class. 您使用了错误的IOHandler类。

TIdIOHandlerStream performs I/O using TStream objects. TIdIOHandlerStream使用TStream对象执行I / O。 It is typically used for replaying previously captured sessions for debugging purposes, without needing a physical connection to a real server. 它通常用于重放先前捕获的会话以进行调试,而无需与真实服务器的物理连接。

You need to use TIdIOHandlerStack instead, which performs I/O using a TCP/IP socket connection. 您需要改用TIdIOHandlerStack ,它使用TCP / IP套接字连接执行I / O。 It is Indy's default IOHandler class, so you don't even need to create an instance of it 1 , TIdTCPClient::Connect() will create one internally for you if you do not assign your own. 它是Indy的默认IOHandler类,因此您甚至不需要创建它的实例1 ,如果您不分配自己的实例, TIdTCPClient::Connect()将为您内部创建一个实例。

1: unless you need more advanced usage, like connecting to a server through a proxy, etc, then you need your own instance so you can configure it as needed. 1:除非需要更高级的用法(例如通过代理连接到服务器等),否则您需要自己的实例,因此可以根据需要对其进行配置。

For what you are attempting, let TIdTCPClient use TIdIOHandlerStack and then you can call the TIdIOHandler::ReadStream() method after connecting to the server. 对于您要尝试的操作,让TIdTCPClient使用TIdIOHandlerStack ,然后在连接到服务器后可以调用TIdIOHandler::ReadStream()方法。 Pass in a TFileStream for it to read into, and set its AByteCount parameter to -1 and AReadUntilDisconnect parameter to True so it will read continuously until the socket connection is closed. 传递一个TFileStream以供其读取,并将其AByteCount参数设置为-1并将AReadUntilDisconnect参数设置为True,这样它将连续读取直到套接字连接关闭。

Also, like most operations in Indy, ReadStream() blocks the calling thread until finished, so to avoid blocking your UI, you should call ReadStream() in a worker thread. 同样,就像Indy中的大多数操作一样, ReadStream()阻塞调用线程直到完成,因此,为了避免阻塞UI,您应该在辅助线程中调用ReadStream() But, if you don't want to use a thread, you can alternately put a TIdAntiFreeze component on your Form instead. 但是,如果您不想使用线程,则可以替代地将TIdAntiFreeze组件放在窗体上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM