Чтение потока данных с использованием TIdIOHandlerStream и TIdTCPClient
У меня есть приложение, которое должно подключиться к серверу с помощью TCP/IP, а затем просто подождать, пока сервер отправит данные, и все, что сервер отправляет, должно быть сохранено в файл.
Вот что я сделал:
Заголовочный файл
#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
и файл 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();
}
Я должен отметить, что IdIOHandlerStream
был установлен как IOHandler
из pTCP
,
Проблема в том, что я знаю, что сервер отправляет много данных, но в файл ничего не записывается.
Кто-нибудь знает почему?
1 ответ
Вы используете неправильный класс IOHandler.
TIdIOHandlerStream
выполняет ввод / вывод, используя TStream
объекты. Обычно он используется для воспроизведения ранее записанных сеансов в целях отладки без физического подключения к реальному серверу.
Вам нужно использовать TIdIOHandlerStack
вместо этого, который выполняет ввод / вывод с использованием сокетного соединения TCP/IP. Это стандартный класс IOHandler для Indy, поэтому вам даже не нужно создавать его экземпляр 1, TIdTCPClient::Connect()
создаст один для вас, если вы не назначите свой собственный.
1: если вам не требуется более сложное использование, например подключение к серверу через прокси-сервер и т. Д., То вам нужен собственный экземпляр, чтобы вы могли настроить его по мере необходимости.
За то, что вы пытаетесь, пусть TIdTCPClient
использование TIdIOHandlerStack
и тогда вы можете позвонить TIdIOHandler::ReadStream()
метод после подключения к серверу. Пройти в TFileStream
для него, чтобы прочитать в и установить его AByteCount
параметр до -1 и AReadUntilDisconnect
Параметр равен True, поэтому он будет считываться непрерывно, пока не будет закрыто сокет
Кроме того, как и большинство операций в Инди, ReadStream()
блокирует вызывающий поток до завершения, поэтому, чтобы избежать блокировки вашего пользовательского интерфейса, вы должны вызвать ReadStream()
в рабочем потоке. Но, если вы не хотите использовать поток, вы можете поочередно поставить TIdAntiFreeze
компонент в вашей форме вместо.