動作環境
C++ Builder XE4
RAD Studio 10.2 Tokyo Update 2 (追記: 2017/12/28)
v0.1を動作確認した
実装内容
- UDPでTLabelのコンポーネント名を受信する
- 取得したコンポーネント名を元にTLabelコンポーネントを探す
- 見つかったコンポーネントのCaption情報を返信する
v0.1
実装
Unit1.h
//---------------------------------------------------------------------------
# ifndef Unit1H
# define Unit1H
//---------------------------------------------------------------------------
# include <System.Classes.hpp>
# include <Vcl.Controls.hpp>
# include <Vcl.StdCtrls.hpp>
# include <Vcl.Forms.hpp>
# include <IdBaseComponent.hpp>
# include <IdComponent.hpp>
# include <IdSocketHandle.hpp>
# include <IdUDPBase.hpp>
# include <IdUDPServer.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TLabel *Label1;
TIdUDPServer *IdUDPServer1;
TMemo *Memo1;
TLabel *L_myIP;
void __fastcall IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
TIdSocketHandle *ABinding);
void __fastcall FormShow(TObject *Sender);
private: // ユーザー宣言
String __fastcall getLabelCaption(String componentName);
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
# endif
Unit1.cpp
//---------------------------------------------------------------------------
# include <vcl.h>
# pragma hdrstop
# include "Unit1.h"
//---------------------------------------------------------------------------
# pragma package(smart_init)
# pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
IdUDPServer1->DefaultPort = 7000;
IdUDPServer1->Active = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
TIdSocketHandle *ABinding)
{
// 1. Receive command (Component name)
String rcvdStr;
Idglobal::_di_IIdTextEncoding encSJIS;
encSJIS = IndyTextEncoding(932);
int init_pos = 0;
rcvdStr = encSJIS->GetString(AData, init_pos, AData.Length);
// for debug
Memo1->Lines->Add(L"rcvd:" + rcvdStr);
// 2. return Caption of the component
String peerIP = ABinding->PeerIP;
int peerPort = ABinding->PeerPort;
String retStr = getLabelCaption(/* componentName=*/rcvdStr);
IdUDPServer1->Send(peerIP, peerPort, retStr, encSJIS);
}
//---------------------------------------------------------------------------
String __fastcall TForm1::getLabelCaption(String componentName)
{
TLabel *lblPtr = (TLabel *)FindComponent(componentName);
if (lblPtr == NULL) {
return L"";
}
return lblPtr->Caption;
}
void __fastcall TForm1::FormShow(TObject *Sender)
{
Label1->Caption = L"From Label1";
// show IP address
TIdStack::IncUsage();
L_myIP->Caption = GStack->LocalAddress;
TIdStack::DecUsage();
}
//---------------------------------------------------------------------------
実行例
L_myIP
というコマンドの応答
192.168.0.31
Label1
というコマンドの応答
From Label1
任意のTLabelコンポーネントに対してCaptionを取得できる。
v0.2 > STX, ETX, BCC追加
変更点
- 応答文字列にコマンド文字列(と",")を追加
-
<STX>
,<ETX>
でペイロードを囲み、<ETX>
の後に<BCC>
を付けるようにした。-
<BCC>
の計算はペイロード+<ETX>
をunsigned charで総和とったもの
-
実装
Unit1.h
//---------------------------------------------------------------------------
# ifndef Unit1H
# define Unit1H
//---------------------------------------------------------------------------
# include <System.Classes.hpp>
# include <Vcl.Controls.hpp>
# include <Vcl.StdCtrls.hpp>
# include <Vcl.Forms.hpp>
# include <IdBaseComponent.hpp>
# include <IdComponent.hpp>
# include <IdSocketHandle.hpp>
# include <IdUDPBase.hpp>
# include <IdUDPServer.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TLabel *Label1;
TIdUDPServer *IdUDPServer1;
TMemo *Memo1;
TLabel *L_myIP;
void __fastcall IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
TIdSocketHandle *ABinding);
void __fastcall FormShow(TObject *Sender);
private: // ユーザー宣言
String __fastcall getLabelCaption(String componentName);
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
# endif
Unit1.cpp
//---------------------------------------------------------------------------
# include <vcl.h>
# pragma hdrstop
# include "Unit1.h"
//---------------------------------------------------------------------------
# pragma package(smart_init)
# pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
/*
v0.2 2017/02/21
- add getWrappedString()
- add calc_bcc()
v0.1 2017/02/21
- add IdUDPServer1UDPRead()
- add getLabelCaption()
- add FormShow()
*/
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
IdUDPServer1->DefaultPort = 7000;
IdUDPServer1->Active = true;
}
//---------------------------------------------------------------------------
static unsigned char calc_bcc(char *srcPtr, int len)
{
// srcPtr: <STX>ペイロード<ETX>の文字列
// ペイロードと<ETX>から<BCC>を計算する
//
unsigned char bcc = 0;
for(int idx=0; idx<len; idx++) {
if (idx==0) {
continue; // <STX>はスキップする
}
bcc += srcPtr[idx];
}
return bcc;
}
static AnsiString getWrappedString(AnsiString srcStr)
{
AnsiString retStr = srcStr;
char szbuf[50] = {0};
szbuf[0] = 0x02; // STX
strncpy(&szbuf[1], srcStr.c_str(), srcStr.Length());
int last = srcStr.Length();
szbuf[++last] = 0x03; // ETX
unsigned char bcc = calc_bcc(szbuf, strlen(szbuf));
szbuf[++last] = bcc;
return AnsiString(szbuf);
}
void __fastcall TForm1::IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
TIdSocketHandle *ABinding)
{
// 1. Receive command (Component name)
AnsiString rcvdStr;
Idglobal::_di_IIdTextEncoding encSJIS;
encSJIS = IndyTextEncoding(932);
int init_pos = 0;
rcvdStr = encSJIS->GetString(AData, init_pos, AData.Length);
// for debug
Memo1->Lines->Add(L"rcvd:" + rcvdStr);
// 2. return Caption of the component
AnsiString peerIP = ABinding->PeerIP;
int peerPort = ABinding->PeerPort;
AnsiString capStr = getLabelCaption(/* componentName=*/rcvdStr);
AnsiString wrpStr = getWrappedString(rcvdStr + L"," + capStr);
IdUDPServer1->Send(peerIP, peerPort, wrpStr, encSJIS);
}
//---------------------------------------------------------------------------
String __fastcall TForm1::getLabelCaption(String componentName)
{
TLabel *lblPtr = (TLabel *)FindComponent(componentName);
if (lblPtr == NULL) {
return L"";
}
return lblPtr->Caption;
}
void __fastcall TForm1::FormShow(TObject *Sender)
{
Label1->Caption = L"From Label1";
// show IP address
TIdStack::IncUsage();
L_myIP->Caption = GStack->LocalAddress;
TIdStack::DecUsage();
}
//---------------------------------------------------------------------------
動作確認
NonSoftさんの「UDP/IPテストツール」を使わせていただきました。
http://nonsoft.la.coocan.jp/Download/UdpTool/index.html
このツールは、ASCII文字列に加えて、<STX>
などの文字を"<STX>
"として表示してくれます。
このため、上記のような通信の確認がしやすくなります。
結果
送-> 192.168.0.31 (7000 )L_myIP
->受 192.168.0.31 (7000 )<STX>L_myIP,192.168.0.31<ETX><b2>
送-> 192.168.0.31 (7000 )L_myIP
->受 192.168.0.31 (7000 )<STX>L_myIP,192.168.0.31<ETX><b2>