- PR -

C#でのバイト列操作について

投稿者投稿内容
Makoto
大ベテラン
会議室デビュー日: 2004/03/31
投稿数: 133
投稿日時: 2004-05-07 15:52
C#初心者です。

C言語で言うところのmemcpyなどの処理は、どのように行えばよいのでしょうか?
例えばソケット通信などで電文を操作する場合、下記の様な構造に対して

@データをコピーする方法
Aデータを取り出す方法

は用意されているのでしょうか?
※もしかして1バイトずつコピーしていくとか?じゃないですよね...

struct item{
int Length;
int TelegramNo;
char TelegramData[32]
};

以上、ご存知の方いらっしゃいましたら、教えてください。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-05-07 16:15
引用:

Makotoさんの書き込み (2004-05-07 15:52) より:
C#初心者です。

C言語で言うところのmemcpyなどの処理は、どのように行えばよいのでしょうか?
例えばソケット通信などで電文を操作する場合、下記の様な構造に対して

@データをコピーする方法
Aデータを取り出す方法

は用意されているのでしょうか?
※もしかして1バイトずつコピーしていくとか?じゃないですよね...

struct item{
int Length;
int TelegramNo;
char TelegramData[32]
};


やり方はいろいろあるんでしょうけど、どうせバイナリなのでしたら、バイナリシリアライズを使うのが常套ではないですかね?
※手っ取り早くて楽。

ちなみにこの構造は、C#言語での定義でも、同じ感じなんでしょうか?
なんとなくCのイメージのままの気がして。
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-05-07 16:30
諸農です。

引用:

Makotoさんの書き込み (2004-05-07 15:52) より:

例えばソケット通信などで電文を操作する場合、下記の様な構造に対して



SocketクラスにはGetStream()メソッドが用意されています。
GetStream()メソッドで取得したNetworkStreamには
Read()/Write()メソッドが用意されております。
実際のデータのやりとり(読み書き)にはこのストリーム
クラスを使うと便利です。

ストリームのRead()/Write()メソッドの引数にはバイト配列を
引き渡します。読み取る際には十分なサイズのバッファを確保
してから行ってください。
Socketクラスには現時点で取得可能なデータサイズを表す
Availableプロパティがあるので、サイズ取得の際に利用されて
みてもいいかと思います。

ネットワークから取得したバイト配列から7bit文字に変換する
にはEncodingクラスのGetString()メソッドを使えばよいです。
また、バイナリデータの送受信をする場合には、ネットワークオ
ーダーを意識する必要があります。
Network-OrderにはIPAddressクラスの
HostToNetworkOrder()/NetworkToHostOrder()を使います。

TCPでバイナリを送受信する場合にStreamReader等を利用する事が
出来ないので注意が必要です。このクラスは文字列操作を対象とし
ていますので。


_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
Makoto
大ベテラン
会議室デビュー日: 2004/03/31
投稿数: 133
投稿日時: 2004-05-07 17:00
回答ありがとうございます。
私の質問の仕方がまずかったみたいで、すみません。

お聞きしたかったのは、
自作した構造のオブジェクトをbyte型へ変換する方法です。
例でいうと、下記main関数内のA処理をどのように記述するかです。

文字型→byteへの変換:Encoding.ASCII.GetBytesを使用
数値型→byteへの変換:BitConverter.GetBytesを使用
が定石かなとは思うのですが、
自作した構造体をそのままbyte列へ変換する方法がわかりません。

class Test{

public struct Header{
public ulong Length;
public byte[] Data1 = new byte[8];
public ulong Data2
public byte[] TelNo = new byte[4];
};

static void main()
{
//@情報を設定
Header head = new Header();
head.Length = 20;
head.Data1 = "DATA1111";
head.Data2 = 2;
head.TelNo = "DATA";

//Aheadを、byte型(ByteData)へ変換する。
//↑この方法がわからない。
byte[] ByteData = new byte[20];

//BSocketクラスを利用して、送信する!←これはわかる。
}
}

以上です。
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-05-07 20:15
こんばんは、meiです。

引用:

Makotoさんの書き込み (2004-05-07 17:00) より:
自作した構造のオブジェクトをbyte型へ変換する方法です。



こんな感じでしょうか?

コード:
using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;

// テスト用構造体
struct Person {
	[MarshalAs(UnmanagedType.ByValArray,SizeConst=8)]
	public byte[] name;
	public int	age;
}

/* C言語上での型
	struct Person {
		char	name	[8];
		int		age;
	};

	[MarshalAs(UnmanagedType.ByValArray,SizeConst=8)]を付けないと
	struct Person {
		char*	name;
		int		age;
	};	
	↑このような型を意味する
*/

class App
{
	[STAThread]
	unsafe static void Main(string[] args)
	{
		Person	person = new Person();
		person.name = new byte [8];
		person.age = 20;

		// 文字列をbyte列へ変換
		byte[] name = Encoding.GetEncoding(932).GetBytes("太郎"); 
		Array.Copy(name, person.name, name.Length);
		// 構造体をサイズを取得し、領域確保
		byte[] dat = new byte[Marshal.SizeOf(person)];
		// ポインタを使わなくても出来るが非効率なので、今回はunsafe使用
		fixed (byte* bp = &dat[0]) {
			Marshal.StructureToPtr(person, (IntPtr)bp, true);
		}
		// 試しにファイルに書いてみる
		FileStream fs = File.OpenWrite("a.dat");
		fs.Write(dat, 0, dat.Length);
		fs.Close();
	}
}



補足ですが、これが出来るのは構造体の場合だけです。
クラスはメモリレイアウトは不明なので・・・(name,ageという並び順も保証されない)
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-05-07 21:00
諸農です。

既にMarshal例のレスポンスがありますが。。

私なら、クラスメンバーフィールドの全部を既定の並び
でbyte配列にして返すメソッドを追加すると思います。


_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2004-05-07 21:12
引用:

私なら、クラスメンバーフィールドの全部を既定の並び
でbyte配列にして返すメソッドを追加すると思います。



同感です。
ToByteArray() とか、標準クラスのデザインを真似した方が人にも説明しやすいし。

あと、データ交換を目的としたシリアライズイメージ(この場合はたまたまバイト列ですが)は memcpy() みたいな実メモリ上のメモリレイアウトをさらけ出すようなあやふやな方法に頼るのではなく、きちんとコードで管理するべきです。

_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#
//
// @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-05-07 21:27
引用:

渋木宏明(ひどり)さんの書き込み (2004-05-07 21:12) より:
あと、データ交換を目的としたシリアライズイメージ(この場合はたまたまバイト列ですが)は memcpy() みたいな実メモリ上のメモリレイアウトをさらけ出すようなあやふやな方法に頼るのではなく、きちんとコードで管理するべきです。


確かにそうするべきですね。

最初の例にC言語の構造体があったので、シチュエーションとして、
相手側に既にCで書かれたプログラムがあって、
それとやり取りするものだとばかり考えて先ほどのような例を示しました。

#メンバーが多かったりアライメントの計算があったり面倒かな・・・っと(^^;

スキルアップ/キャリアアップ(JOB@IT)