1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C++ Builder XE4 > TCP > Clientからの送信と受信処理 > v0.1:whileでの受信タイムアウト, v0.2:ReadLn()での受信タイムアウト | 余談: 記事消した...

Last updated at Posted at 2018-01-11
動作環境
C++ Builder XE4

処理概要

  • TCPサーバーに接続する
  • TCPサーバーに文字列を送信する
  • TCPサーバーからの応答を受信する
    • タイムアウト付き

code v0.1 (Whileでの受信待ち)

備考: E_ipadrとE_portはPasswordCharを設定している

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 <IdTCPClient.hpp>
#include <IdTCPConnection.hpp>
#include <Vcl.ComCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TEdit *E_ipadr;
	TButton *Button1;
	TIdTCPClient *IdTCPClient1;
	TLabel *Label1;
	TLabel *Label2;
	TEdit *E_port;
	TLabel *Label3;
	TEdit *E_sendText;
	TStatusBar *StatusBar1;
	void __fastcall Button1Click(TObject *Sender);
private:	// ユーザー宣言
	void __fastcall commTCP(int timeout_msec);
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)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::commTCP(int timeout_msec)
{
	// 1. Connect
	IdTCPClient1->Host = E_ipadr->Text;
	int portNum = StrToIntDef(E_port->Text, -1);
	if (portNum < 0) {
		String wrnmsg = L"Error: Invalid port number:" + E_port->Text;
		MessageDlg(wrnmsg, mtError, TMsgDlgButtons() << mbOK, 0);
		return; // fail to get portNum
	}
	IdTCPClient1->Port = portNum;
	try {
		IdTCPClient1->Connect();
	} catch (...) {
		String wrnmsg = L"Failed to connect to " + E_ipadr->Text;
		MessageDlg(wrnmsg, mtError, TMsgDlgButtons() << mbOK, 0);
		return;
	}

	// 2. send
	String sndTxt = E_sendText->Text;
	IdTCPClient1->IOHandler->WriteLn(sndTxt);

	// 3. receive
	String rcvd;
	DWORD startTim = GetTickCount();
	while(1) {
		if (GetTickCount() - startTim > timeout_msec) {
			String wrnmsg = L"Error: Receive timeout";
			MessageDlg(wrnmsg, mtError, TMsgDlgButtons() << mbOK, 0);
			break;
		}
		if (IdTCPClient1->IOHandler->InputBufferIsEmpty() == false) {
			Application->ProcessMessages();
			Sleep(100);
			continue;
		}
		if (IdTCPClient1->IOHandler->CheckForDataOnSource(100) == false) {
			Application->ProcessMessages();
			continue;
		}

		//int size = IdTCPClient1->IOHandler->InputBuffer->Size;

		rcvd = IdTCPClient1->IOHandler->ReadLn();
		String infmsg = L"Received: " + rcvd;
		MessageDlg(infmsg, mtInformation, TMsgDlgButtons() << mbOK, 0);
		break;
	}

	IdTCPClient1->IOHandler->InputBuffer->Clear();
	IdTCPClient1->Disconnect();
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
	IdTCPClient1->ConnectTimeout = 2000; // msec
	IdTCPClient1->ReadTimeout = 2000; // msec

	commTCP(/*timeout_msec=*/1000);
}
//---------------------------------------------------------------------------

実行例

A. 相手先がListenしていない

qiita.png

B. 相手先がListenしている, 応答しない

qiita.png

C. 相手先がListenしている, 応答する

qiita.png

備考

  • 接続、送信、受信を一括にしているため、他の処理がブロックされる
  • 受信タイムアウトはGetTickcount()での処理
    • ReadTimeoutを使った処理は未消化

使用ツール

関連記事

余談: 記事消した

苦労して記載した記事を間違って消してしまった。

@ 生きるのが楽しくなる15の習慣 by 日野原重明さん

p81 トーマス・カーライルの名著「フランス革命史」
そこで事件は起こりました。友人の家のお手伝いさんが、それを書き損じの原稿と勘違いし、ストーブで燃やしてしまったのです。
それを知ったカーライルはひどく落胆し、やはり「もう同じものは書けない」と気力も失ってしまったとのことでした。
ところが、彼の妻は立派でした。夫に同情しながらも、きっぱりこう言ったそうです。
「このまま書かないですむくらいなら、最初から書く必要がなかったものなのよ」
カーライルはこの言葉に奮起しました。なぜなら、それはカーライルにとってどんなことをしても書かなければならないテーマだったからです。彼は再び机に向かい、そして誕生した本は、160年以上の年月を経た今なお、世界の名著とたたえられています。

code v0.2 > ReadLn()での受信待ち

ReadLn()において受信タイムアウトを指定できるようだ。

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

/*
v0.2 2018/01/11
	- ReadLn()の引数での受信タイムアウト処理
v0.1 2018/01/11
	- whileでの受信タイムアウト処理
*/

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::commTCP(int timeout_msec)
{
	// 1. Connect
	IdTCPClient1->Host = E_ipadr->Text;
	int portNum = StrToIntDef(E_port->Text, -1);
	if (portNum < 0) {
		String wrnmsg = L"Error: Invalid port number:" + E_port->Text;
		MessageDlg(wrnmsg, mtError, TMsgDlgButtons() << mbOK, 0);
		return; // fail to get portNum
	}
	IdTCPClient1->Port = portNum;
	try {
		IdTCPClient1->Connect();
	} catch (...) {
		String wrnmsg = L"Failed to connect to " + E_ipadr->Text;
		MessageDlg(wrnmsg, mtError, TMsgDlgButtons() << mbOK, 0);
		return;
	}

	// 2. send
	String sndTxt = E_sendText->Text;
	IdTCPClient1->IOHandler->WriteLn(sndTxt);

	// 3. receive
	String rcvd;
	rcvd = IdTCPClient1->IOHandler->ReadLn(L"", timeout_msec);
	if (rcvd.Length() > 0) {
		String infmsg = L"Received: " + rcvd;
		MessageDlg(infmsg, mtInformation, TMsgDlgButtons() << mbOK, 0);
	} else {
		String wrnmsg = L"Error: Receive timeout";
		MessageDlg(wrnmsg, mtError, TMsgDlgButtons() << mbOK, 0);

	}

	IdTCPClient1->IOHandler->InputBuffer->Clear();
	IdTCPClient1->Disconnect();
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
	IdTCPClient1->ConnectTimeout = 2000; // msec
	IdTCPClient1->ReadTimeout = 2000; // msec

	commTCP(/*timeout_msec=*/1000);
}
//---------------------------------------------------------------------------
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?