C ++ Builder отправляет массив с использованием TCP - PullRequest
0 голосов
/ 25 апреля 2018

В C ++ Builder я должен отправить многомерный массив int, например:

int example[3][3];

с использованием протокола TCP.

Я создал сокет, используя это видео:

https://www.youtube.com/watch?v=UjrITeDk718

Но я не понимаю, как отправить просто многомерный массив вместо строки ... Любой намек?

КОД КЛИЕНТА:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  IdTCPClient1->Connect();
  //send byte
  IdTCPClient1->WriteInteger(Edit1->Text.Length());
  //send text
  IdTCPClient1->Write(Edit1->Text);


  //send request
  TStringList *SL = new TStringList;
  SL->Add(Edit1->Text);
  IdTCPClient1 ->WriteStrings(SL);
  delete SL;
  ListBox1->Items->Add(Edit1->Text+">>sent");


  int bytes = IdTCPClient1 -> ReadInteger();
  AnsiString resp = IdTCPClient1->ReadString(bytes);
  ListBox1->Items->Add(resp);
  IdTCPClient1->Disconnect();

}
//---------------------------------------------------------------------------

КОД СЕРВЕРА:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdTCPServer1Execute(TIdPeerThread *AThread)
{
  int bytes =  AThread->Connection->ReadInteger();

  AnsiString request = AThread->Connection->ReadString(bytes);
  ListBox1->Items->Add(request);

  Edit1->Text=FormatDateTime("hh:mm AM/PM", Now());
  AnsiString risp = Edit1->Text;

  AThread->Connection->WriteInteger(risp.Length());
  TStringList *SL = new TStringList;
  SL->Add(risp);
  AThread->Connection->WriteStrings(SL);
  delete SL;
  ListBox1->Items->Add(risp+">> inviato");
  AThread->Connection->Disconnect();
}
//---------------------------------------------------------------------------

1 Ответ

0 голосов
/ 25 апреля 2018

Независимо от того, сколько измерений использует ваш массив, он по-прежнему имеет фиксированный размер в байтах (sizeof(int) * 3 * 3 = 36), поэтому вы можете использовать методы TIdTCPConnection::WriteBuffer() и TIdTCPConnection::ReadBuffer() для его отправки / получения, например:

IdTCPClient1->WriteBuffer(&example, sizeof(example));

AThread->Connection->ReadBuffer(&example, sizeof(example));

Но, если вы не хотите на это полагаться, вы можете отправлять / получать значения int по отдельности, используя методы TIdTCPConnection::WriteInteger() и TIdTCPConnection::ReadInteger(), например:

for (int i = 0; i < 3; ++i)
{
    for (int j = 0; j < 3; ++j)
        IdTCPClient1->WriteInteger(example[i][j]);
}

for (int i = 0; i < 3; ++i)
{
    for (int j = 0; j < 3; ++j)
        example[i][j] = AThread->Connection->ReadInteger();
}

Если вместо этого вы используете динамически распределенный массив, вы можете затем отправить отдельные измерения перед отправкой действительных целых чисел, чтобы получатель знал, сколько целых чисел ожидать, чтобы он мог выделить подходящий массив для их получения, например:

IdTCPClient1->WriteInteger(3);
IdTCPClient1->WriteInteger(3);

for (int i = 0; i < 3; ++i)
{
    for (int j = 0; j < 3; ++j)
        IdTCPClient1->WriteInteger(example[i][j]);
}

rows = AThread->Connection->ReadInteger();
cols = AThread->Connection->ReadInteger();

example = new int*[rows];
for (int i = 0; i < rows; ++i)
{
    example[i] = new int[cols];
    for (int j = 0; j < cols; ++j)
        example[i][j] = AThread->Connection->ReadInteger();
}

При этом, есть несколько проблем с кодом, который вы показали.

  • Ваш клиент и сервер не совпадают:

    • Ваш клиент отправляет AnsiString с префиксом длины, за которым следует (не с префиксом счетчика) TStringList. Затем он читает AnsiString с префиксом длины.

    • Ваш сервер правильно читает AnsiString с префиксом длины клиента, но игнорирует TStringList клиента. Затем он отправляет длину AnsiString, но не отправляет сам AnsiString, за которым следует (не с префиксом) TStringList. Клиент не будет правильно читать TStringList.

  • Ваш обработчик TIdTCPServer :: OnExecute не синхронизируется с основным потоком пользовательского интерфейса при доступе к элементам управления пользовательского интерфейса. TIdTCPServer - это многопоточный компонент, его события запускаются в контексте рабочих потоков, а не основного потока пользовательского интерфейса. Вы ДОЛЖНЫ синхронизироваться при доступе к пользовательскому интерфейсу из рабочего потока, иначе произойдет что-то плохое.

Попробуйте вместо этого:

Клиент:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    String s = Edit1->Text;

    int example[3][3];
    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 3; ++j)
           example[i][j] = (i*3)+j;
    }

    IdTCPClient1->Connect();
    try
    {
        //send byte length
        IdTCPClient1->WriteInteger(s.Length());
        //send text
        IdTCPClient1->Write(s);

        // send array
        IdTCPClient1->WriteBuffer(&example, sizeof(example));

        ListBox1->Items->Add(s + ">>sent");

        int bytes = IdTCPClient1->ReadInteger();
        String resp = IdTCPClient1->ReadString(bytes);
        ListBox1->Items->Add(resp);
    }
    __finally
    {
        IdTCPClient1->Disconnect();
    }
}
//---------------------------------------------------------------------------

Сервер:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <IdSync.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
class TAddToListBoxSync : public TIdSync
{
public:
    String str;
    __fastcall TAddToListBoxSync(const String &s) : TIdSync(), str(s) {}
    virtual void __fastcall DoSynchronize() { Form1->ListBox1->Items->Add(str); }
};

class TSetEditTextSync : public TIdSync
{
public:
    String str;
    __fastcall TSetEditTextSync(const String &s) : TIdSync(), str(s) {}
    virtual void __fastcall DoSynchronize() { Form1->Edit1->Text = str; }
};
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdTCPServer1Execute(TIdPeerThread *AThread)
{
    int bytes = AThread->Connection->ReadInteger();
    String request = AThread->Connection->ReadString(bytes);

    int example[3][3];
    AThread->Connection->ReadBuffer(&example, sizeof(example));

    TAddToListBoxSync *lb_sync = new TAddToListBoxSync(request);
    try {
        lb_sync->Synchronize();
    }
    __finally {
        delete lb_sync;
    }

    String risp = FormatDateTime("hh:mm AM/PM", Now());

    TSetEditTextSync *edt_sync = new TSetEditTextSync(risp);
    try {
        edt_sync->Synchronize();
    }
    __finally {
        delete edt_sync;
    }

    AThread->Connection->WriteInteger(risp.Length());
    AThread->Connection->Write(risp);

    lb_sync = new TAddToListBoxSync(risp + ">> inviato");
    try {
        lb_sync->Synchronize();
    }
    __finally {
        delete lb_sync;
    }

    AThread->Connection->Disconnect();
}
//---------------------------------------------------------------------------
...