Indy9のUDPの送受信がうまくいかない

解決


osa  2005-11-29 06:33:44  No: 18921

Indy9のTIdUDPClient,TIdUDPServerで送受信を
したいのですがうまくいきません
SendBufferでクライアントからデータを送って
サーバーで受け取ったときに値がいつも変化してしまいます
原因がさっぱり分かりません
以下にソースを書きますが間違っているのでしょうか?
(クライアントのHostはLocalHostにしています)

procedure TForm1.Button1Click(Sender: TObject);
var
  data: TMemoryStream;
  i: Integer;
begin
  data:=TMemoryStream.Create;
  i:=1;
  data.WriteBuffer(i,1);
  IdUDPClient1.SendBuffer(data,1);
  data.Free;
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
var
  Data: TMemoryStream;
  i: Integer;
begin
  Data:=TMemoryStream.Create;
  Data.CopyFrom(AData,AData.Size);
  Data.Position:=0;
  Data.ReadBuffer(i,1);
  Label1.Caption:=IntToStr(i);
  Data.Free;
end;


どやさ  2005-11-30 19:04:04  No: 18922

>  IdUDPClient1.SendBuffer(data,1);
送り側(TMemoryStream の使い方)が完全にまちがっていますね。
IdUDPClient1.SendBuffer(data^,1);

>  data.WriteBuffer(i,1);
>  IdUDPClient1.SendBuffer(data,1);
送り側のこの部分ですけど位置を元に戻してください

data.WriteBuffer(i,1);
data.Position := 0;    // ←追加
IdUDPClient1.SendBuffer(data,1);

TMemoryStream の使い方を理解して使用する場合は
注意してください。うまく動かないときには型と位置の
確認をすることです。

>  Data:=TMemoryStream.Create;
>  Data.CopyFrom(AData,AData.Size);
>  Data.Position:=0;
>  Data.ReadBuffer(i,1);
>  Label1.Caption:=IntToStr(i);
>  Data.Free;
おせっかいですが、無駄なことしてますね
わざわざData を作ることも、コピーすることも必要ないかと・・・
AData.Position := 0;
AData.ReadBuffer(i, 1);

>  data:=TMemoryStream.Create;
>  i:=1;
>  data.WriteBuffer(i,1);
>  IdUDPClient1.SendBuffer(data,1);
>  data.Free;
もうひとつおせっかいでしょうが
このそーすでは以下ですみそうです。
IdUDPClient1.SendBuffer(i, 1);


osa  2005-12-01 06:05:14  No: 18923

返信ありがとうございます
以下のようにソースを直しましたがやはり値が変動してしまいます
たまに正しい値になりますが・・
まだ何か問題があるのでしょうか?
ちなみにバイナリデータを送受信できれば
TMemoryStreamを使わなくてもいいのですが
他によい方法があれば教えていただきたいです

procedure TForm1.Button1Click(Sender: TObject);
var
  data: TMemoryStream;
  i: Integer;
begin
  i:=StrToInt(Edit1.Text);
  data:=TMemoryStream.Create;
  data.WriteBuffer(i,1);
  data.Position := 0;
  IdUDPClient1.SendBuffer(data.Memory^,1);
  data.Free;
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
var
  i: Integer;
begin
  AData.Position := 0;
  AData.ReadBuffer(i, 1);
  Label1.Caption:=IntToStr(i);
end;


どやさ  2005-12-01 21:00:48  No: 18924

プログラムの目的がわからないので確認ですが、

このプログラムで送信できるのは i の値の下位バイトの1バイトです
i = $12345678 (i は Integer なので4バイト)のデータを送信すると、
受信できる i = $78 です。
例>
    送信            受信
  i := 0..255;   i := 0..255; 
  i := 256..511; i := 0..255; 

もし、送信と、受信の i を同じにしたいのであれば、
基本的にソース(考え方)がまちがっているのですが、
そうじゃないですよね?


osa  2005-12-02 02:41:39  No: 18925

例のように送受信がされていいのですが、
iに1を入れて送信すると受信したときに
ラベルに12452233や13238787のような数字が表示されます
何度かボタンをクリックしていると1になるときもあります


だからぁ  2005-12-02 10:12:07  No: 18926

iに1バイトしか読んだけでは32ビット整数の上位24ビットには何が入っているか保証されないよ・・・ということなのですが
---
i :=0;
AData.ReadBuffer(i, 1);
---
としたらどう?


どやさ  2005-12-02 21:36:22  No: 18927

Integer がわかっていないようですね。

メモリ上  ・・・ 12 34 56 78 90 AB CD EF ・・・
                    ←   i   →
                    i は Integer なので4バイトです

i := 1    ・・・ 12 34 01 00 00 00 CD EF ・・・
              メモリ上は上位下位が反転して入ります。

i の1バイトを送信すると1が送られます。
理論上間違っていないが、通常1バイトを送るなら
i: Integer; の宣言を  SendByte: Byte;  として
data.WriteBuffer(i,1);  →  data.WriteBuffer(SendByte,1);
                          または  data.WriteBuffer(SendByte, SizeOf(Byte));
                          とします。

受信側です。
メモリ上  ・・・ AA BB 11 22 33 44 55 66 ・・・
                    ←   i   →

ここで、AData.ReadBuffer(i, 1); が実行されると
メモリ上  ・・・ AA BB 01 22 33 44 55 66 ・・・
                    ↑
                    i の先頭番地のデータ1バイトが変わる

つまり、  i の値は  $44332201 となります。

強いていえば、あなたの仕様を損なわないようにするには

i := 0;                  ← 追加してください
AData.ReadBuffer(i, 1);

お分かり?


osa  2005-12-03 07:27:30  No: 18928

とりあえずやりたいことはできるようになりました
ありがとうございます

原因は何となく分かるような分からないような・・
もっと勉強します


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加