2012年11月16日

いろいろ、迷走

08/10/18(Sat) 09:04
MemoryStreamのなぞ

以前も疑問だったのだが、bitmapをSaveToStreamでMemoryStreamにsaveした後、LoadFromStreamで別のbitmapにloadすることができない。SaveToFileの場合はLoadFromFileができる。Streamとはメモリ上にあるだけでファイルと同様に扱えるのではないのか?

08/10/18(Sat) 09:15
解決。

Streamの場合、saveした後positionが書き込んだ最後の位置になっているので、0に戻す必要がある。ファイルの場合はその必要がないのにな・・・。なんか納得したようなしないような・・・。ポジションがどうの、という話は聞いたことはあったんだけど、この場合にそれが該当するとは気づかなかった・・・。ソースは2チャンネルである。クソッ!

08/10/19(Sun) 08:10
Indy10 UDPServerの sendbuffer

ビットマップファイルを用意して、それをストリームにloadし、そのストリームをbufferに読み込み、それをUDPServerでsendbufferしてみた。しかし、READするたびに例外が出て、sendbufferするもののmalformedパケットになってしまう。原因はsendbufferする前の、streamのreadで、bufサイズが設定されていないことであった。

procedure TForm1.Button6Click(Sender: TObject);
var
buf: TBytes;
BytesRead: Longint;
begin
SetLength(buf,4096);
MyStream.Position:=0;
MyStream.Read(Pointer(buf)^,4096);
IdUDPServer1.SendBuffer(Edit1.Text,MyPort,buf);
end;

このように、SetLengthでバッファサイズを設定しないとだめだ。ちなみに4096バイトをsendbufferしたら、ちゃんとフラグメントされて3つのパケットが送信された。感動。

08/10/19(Sun) 08:19
あとは、streamの終了判定をして全部送信し、受信側ではstreamに書き出し、imageにloadfromstreamをすれば、画像が表示されるはずだ。バッファのサイズはどれくらいが適当なんだろうか?小さすぎれば何度も読むことになるし、大きすぎれば無駄な通信が発生することになる。ちなみにFTPでアップロードした、640x480サイズのデスクトップをキャプチャしたJPGファイルのサイズは84KBだった。

08/10/19(Sun) 08:22
今気づいたんだが、codezineのサンプルでやった文字列の送受信は、ほぼip messenger的なアプリなんじゃないのか?

08/10/19(Sun) 11:33
なんとか画像を転送することができた・・・。だが、なぜか8KBほどのサイズまでしか送れない。あと、2台で動作確認してみようと思ったら、一部動かない機能が。無理もない、だってVistaで作ったファイルだからね。XPで動かなくても。

08/10/19(Sun) 11:34
ものすごく恥ずかしいけど、ソース載せときますね。

unit udpsUnit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase,
IdSocketHandle,IdGlobal,
IdUDPClient, ExtCtrls;

type
TForm1 = class(TForm)
IdUDPClient1: TIdUDPClient;
Button1: TButton;
IdUDPServer1: TIdUDPServer;
Memo1: TMemo;
Button2: TButton;
Edit1: TEdit;
Image1: TImage;
Button3: TButton;
Button6: TButton;
Image3: TImage;
Button7: TButton;
Memo2: TMemo;
FileOpenDialog1: TFileOpenDialog;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure IdUDPServer1UDPRead(Sender: TObject; AData: TIdBytes; ABinding: TIdSocketHandle);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure Button7Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
MyPort: Integer;
TxBuf, RxBuf: TIdBytes;
bmp: TBitMap;
MyStream: TMemoryStream;
RxStream: TMemoryStream;
MyBmp: String;
bufsize: Integer;

implementation

{$R *.dfm}



procedure TForm1.Button1Click(Sender: TObject);
begin
IdUDPServer1.Broadcast('Anybody there?',12345);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
IdUDPServer1.Send(Edit1.Text,12345,'Are you there?');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
// Image1.Picture.Assign(bmp);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
// bmp.SaveToStream(MyStream);
// Image1.Picture.Bitmap.SaveToStream(MyStream);
end;


procedure TForm1.Button6Click(Sender: TObject);
var
BytesRead: Longint;

begin
MyStream.Clear;

FileOpenDialog1.Execute;

bmp.LoadFromFile(FileOpenDialog1.FileName);
Image1.Picture.Assign(bmp);
Image1.Picture.Bitmap.SaveToStream(MyStream);


SetLength(TxBuf,bufsize);
SetLength(RxBuf,bufsize);

MyStream.Position:=0;

BytesRead:=MyStream.Read(Pointer(TxBuf)^,bufsize);
while BytesRead>0 do
begin
Memo1.Lines.Add('BytesRead: '+IntToStr(BytesRead));
if (BytesRead4096 do
begin
IdTCPClient1.IOHandler.ReadStream(sv,4096);
inc(FileSize,-4096);
end;
IdTCPClient1.IOHandler.ReadStream(sv,FileSize);
sFile.Free;
end;

08/10/21(Tue) 04:40
ファイルを送るときに、fileopendialogで選択しているのだが、そこをファイル名直接指定だとなぜか開けない。今日はこのくらいで。

08/10/21(Tue) 20:50
udpでだらだら送る方式からTCPを検討して、テキストは簡単だけどある程度の大きさの画像ファイルの転送は難しいな・・・と、今朝顔を洗っているときに、FTPでいいんじゃないかという気がしてきた。その名の通り、ファイルを転送するためのプロトコルである。
高速化したいならTFTPという手もある。さらに、それを多数のクライアントに対しておこなうのがHTTPなんじゃないか。

まあ、それらのコンポーネントを使わないにしても、バイナリファイルの扱いはソースを見ればわかるからそれをマネしてもいいし。

08/10/21(Tue) 20:52
htxp://www.ipc.hokusei.ac.jp/~z00104/delphi/exercise12.html
にあるけど、
socketstreamというものがあって、それを使えば、SaveToStream(socketstream)というように、
ファイルを保存する感覚で転送できるぞ!
受信側はloadfromstreamすればよい。
このsocketなんとかというコンポーネントは、indyが無い時代のコンポーネントである。
2.0からあったかな?もっと後かな?
わたしには歯が立たず、indyになってようやく使えるようになった。

ところで、このように自分でソケットをどうこうする通信というのは、TCPでもUDPでもないよね?
これはただのIPパケットということになるのか?

08/10/21(Tue) 23:01
FTPサーバを使ってみた・・・・が、複雑怪奇、さっぱりわからん。
とりあえず起動して、クライアントからつないで、パスワードもチェックせずにログインできた。
だが、ファイルの送受信をどうやるのか、さっぱりわからん。indyのサンプルを落としてきたがコンパイルできず意味不明なエラーになる。

08/10/22(Wed) 20:37
夕べはほとんど何もできなかった。FTPサーバ・クライアントのサンプルがコンパイルできない。とりあえず適当に、IdFTPServerのプロパティやメソッドをいじってみた。Windowsのコマンドプロンプトでftpコマンドを打つと、パスワードもいれずにログインできた。認証する処理を書かねばならないのだろう。とりあえず認証はいらない。だが、ログインした後、ディレクトリをリストしたり、ファイルを受け取ったりすることができない。putしてみたらエラーが表示されるが文字化けしていて、サーバー側にはエラーが出たりする。

しかし、やっぱり、ストリーミング的なものを作ってみたい。その手のソフトはいくらでもある。一体どうやってやっているんだろう?まずは、それらのソフトが送受信しているパケットをキャプチャして研究するところから始めるかな。気が遠くなる。


08/10/22(Wed) 21:16
とりあえずリモートデスクトップをキャプチャしてみたが、TCPですね。

08/10/22(Wed) 22:14
indyのFTPデモ。9のデモは、delphi7+indy9でコンパイルして実行できる。
indy10のデモは、serverがない。

9のデモを2007でコンパイルすると、TIdFTPServerThreadが未定義というエラーになる。その他にも未定義がある。

もうメンドクセエ、寝る。


posted by delsoli at 18:37| delphi | 更新情報をチェックする
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。