0
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.

2017-02-14 C++ Builder XE4 / Socket > ReceiveBuf()では0x00を途中に含めた指定長さの文字列を受信する / ReadBytes()では0x00までの長さの文字列だけを受信する > ReadChar()試用 / ReadString() + memcpy()使用 > ReadStream()使用

Last updated at Posted at 2017-02-14
動作環境
C++ Builder XE4

TClientSocketにて通信断が発生する状況の対処を検討している。
TClientSocketからIndyのTIdTCPClientに変更をしようとしている。

  1. ClientSocket->Socket->ReceiveBuf(void *Buf, int Count);
  2. IdTCPClient1->Socket->ReadBytes()で置き換えようとした。

方法1の場合は、hello<0x00>worldという文字列が来た時には、worldまで受信できた。
方法2の場合は、hello<0x00>までの受信となった。

受信方法を変更することになる。

ReadChar()試用

変更点

IndyのSocketにはReadChar()があるようだ。

Unit1.cpp
	char zbuf[50] = { 0 };
	char code;
	for(int idx=0; idx < len; idx++) {
		code = IdTCPClient1->Socket->ReadChar();
		zbuf[idx] = code;
	}

上記で読込みができた。

トラブル

ReceiveBuf()を使っていた時は、20文字の読取りに対してGetTickCount()では0となるほどの速度で処理される。

一方で、ReadChar()を使うとfor()で20回まわして同じ処理で2940msecかかるようだ。
20文字でなく18文字までの読取りでは0msecで処理される。

20文字の読込みでは11文字目まではReceiveBuf()とReadChar()で同じ。12文字目以降は以下のように異なっている。

  • ReceiveBuf()受信
    • 0xE0 0x00 0xEA 0x00 0x00 0x00 0x00 0x00 0x0F
  • ReadChar()受信
    • 0xFD 0xFD 0x00 0x00 0x00 0x00 0x0F 0x4C 0x43

本来0x0Fで終端するはずが、ReadChar()では18文字目で終端文字列を読込んでしまっている。
この部分がおかしい。

ReadString()使用

ReadString() + memcpy()

ReadChar()の繰返しでは読み落としが生じていると推測した。
別の方法としてReadString()を使うことにした。

ReadString()で受信するString型文字列をchar []型に変換する方法としてstrncpy()を試した。この場合、0x00が途中にあるとそこまでのコピーしかされない。

色々試したところ、memcpy()だと途中に0x00があっても、指定の長さを取得できることが分かった。

Unit1.cpp
	AnsiString str = IdTCPClient1->IOHandler->ReadString(len);
	char zbuf[50] = { 0 };
	//strncpy(zbuf, str.c_str(), len);
	memcpy(zbuf, str.c_str(), len);

これでReceiveBuf()と同じ受信処理となった。

トラブル

上記で受信できたと思ったが、20文字中の2文字 (0xE0, 0xEA)が(0x3F, 0x3F)として認識されてしまう問題が生じている。

ReadStream()使用

ReadString()では128以上のコードが本来のコードでなく変換されてしまうことが分かった。
http://qiita.com/7of9/items/7bab0cf9f4311f1ebbd1

ReadString()でなく、ReadStream()を使ってみた。

Unit1.cpp
	TMemoryStream *strm = new TMemoryStream();
	IdTCPClient1->IOHandler->ReadStream(strm, len);
	strm->Seek(0, 0); // 先頭に移動
	char zbuf[50] = { 0 };
	strm->ReadData(zbuf, len);
	delete strm;

こちらでは20文字すべて、ReceiveBuf()使用時と同じになった。

strmの定義にはunique_ptrを使うのが良い。

0
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
0
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?