【问题标题】:C++Builder send array using TCPC++Builder 使用 TCP 发送数组
【发布时间】:2018-05-18 00:50:14
【问题描述】:

在 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();
}
//---------------------------------------------------------------------------

【问题讨论】:

  • 您还没有显示所有代码。 IdTCPClient1 是什么?请参阅 minimal reproducible example 并考虑创建一个来改进您的问题。
  • 它只是C++ Builder的一个组件,如果您从Indy Clients中选择TCP Client,IdTCPClient1是标准名称... :)
  • 了解,但忽略这一点会使没有 C++ Builder 并且没有大量额外时间观看 YouTube 视频的人(例如我自己)难以或不可能帮助诊断您的问题。
  • @BlueFab 仅供参考,您的代码使用的是 Indy 9,它已经过时了十多年。请考虑升级到 Indy 10。

标签: c++ tcp c++builder


【解决方案1】:

无论您的数组使用多少维,它仍然具有固定的字节大小(sizeof(int) * 3 * 3 = 36),因此您可以使用TIdTCPConnection::WriteBuffer()TIdTCPConnection::ReadBuffer() 方法来发送/接收它,例如:

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

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

但是,如果您不想依赖它,那么您可以使用 TIdTCPConnection::WriteInteger()TIdTCPConnection::ReadInteger() 方法单独发送/接收 int 值,例如:

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。

  • 在访问 UI 控件时,您的 TIdTCPServer::OnExecute 处理程序未与主 UI 线程同步。 TIdTCPServer 是一个多线程组件,它的事件是在工作线程的上下文中触发的,而不是主 UI 线程。从工作线程访问 UI 时必须同步,否则会发生坏事。

试试这个:

客户:

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

#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();
}
//---------------------------------------------------------------------------

【讨论】:

    猜你喜欢
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 2015-09-03
    • 2017-09-14
    • 2016-04-27
    • 2012-03-14
    • 2011-11-03
    • 1970-01-01
    相关资源
    最近更新 更多