記事の概要:
Delphi は強力です。Delphi を使用してソフトウェアを作成すると、ソフトウェア開発サイクルを大幅に短縮できます。この記事では、Delphi を使用してポイントツーポイント ファイル転送プログラムを作成する方法を紹介します。
-----------------------------------------------
Delphi は強力です。Delphi を使用してソフトウェアを作成すると、ソフトウェア開発サイクルを大幅に短縮できます。ポイントツーポイント ファイル転送の基本的な考え方は、サーバー ソフトウェアとクライアント ソフトウェアが接続された後、ファイル名、サイズなどを含むリクエストをサーバーに送信することです。サーバーが転送するファイルを受け入れて転送を開始する場合。もちろん、ファイル転送には ASCII コードと Bin の 2 つのモードがありますが、一般的には Bin で十分です。上記の議論に基づいて、本来は Delphi4 の NMStrm および NMStrmServ コントロールを使用して実行できましたが、テストしたところ、NMStrm コントロールは小さいファイルには引き続き使用でき、非常に便利ですが、ファイルが大きい(1M)場合は便利であることがわかりました。 、エラーが発生します。次に、Delphi で TServerSocket と TClientSocket を使用してこのプログラムを作成します。これは、イーサネット パケット サイズの制限と DelphiSocket の処理メカニズムのため (Delphi では、Socket を使用して大きなストリームを送信すると、受信側が OnRead を複数回トリガーします)。 。 Delphi は、複数の OnRead イベント内の各データの整合性を保証するだけであり、データ自体を収集してユーザーに返すことはありません。そのため、転送対象のファイルを 1 つの Socket で 1 回送信し、1 回 Recv で送信できるとは考えないでください。データを自分で収集するか、プロトコルを定義する必要があるため、カスタム プロトコル方式を採用します。プロトコルを定義する標準的な方法は、Record End を使用することです。のように:
TMyFilePROtocol=レコード
sSendType=(ST_QUERY,ST_REFUSE,ST_DATA,ST_ABORT,...);
iLength:整数;
bufSend:バッファ;
終わり;
この方法を試してみましたが、失敗しました。自分の方法が正しいと常に思っていましたが、プログラムは常にコンパイルに失敗しました。Delphi に何か問題があったようです:) そこで、次のサンプル プログラムでは別の方法を使用しました。 Socket クラスには ReceiveText と ReceiveBuf という 2 つのプロパティがあります。OnRead イベントでは、これら 2 つのプロパティは 1 回しか使用できないため、グローバル変数を使用して Text を読み取るか Buf を読み取るか、つまり読み取りを保存できます。一度テキストを送信し、再度読み取ります。これは TMyFileProtocol をシミュレートします。
プログラムを開始します。
主にメソッドの説明に使用される、最も単純なものを書きます。
プロトコルを定義します。
定数
MP_QUERY ='1';
MP_REFUSE ='2';
MP_ACCEPT = '3';
MP_NEXTWILLBEDATA='4';
MP_DATA ='5';
MP_ABORT ='6';
MP_OVER ='7';
MP_CHAT ='8';
契約の概要:
まず、クライアントは MP_QUERY を送信し、それを受信した後、サーバーは MP_ACCEPT または MP_FEFUESE を送信します。
クライアントは MP_ACCEPT を受信した後に MP_FILEPROPERTY を送信し、サーバーはそれを受信した後に MP_NEXTWILLBEDATA を送信します。
クライアントは MP_NEXTWILLBEDATA を受信後に送信し、サーバーは MP_DATA を受信後に送信します。
クライアントは MP_DATA を受信してデータを送信し、サーバーはデータを受信して MP_NEXTWILLBEDATA を送信します。
クライアントが MP_OVER を送信するまでループします。
MP_CHAT+String は途中で相互に送信できます。
サーバープログラム:
次のコントロールを配置します:SaveDialog1、btnStartServer、
ss,(TServerSocket)
btnStartServer.OnClick(Sender:TObject);
始める
ss.ポート:=2000;
ss.開く;
終わり;
ss.OnClientRead(送信者: TObject;ソケット: TCustomWinSocket);
変数
sTemp:文字列;
bufRecv:ポインタ;
iRecvLength:整数;
始める
bReadText の場合
始める
sTemp:=Socket.ReceiveText;
ケースの温度[1]
MP_QUERY:開始
//ここで拒否
SaveDialog1.FileName:=Copy(sTemp,2,Length(STemp));
SaveDialog1.Execute の場合
始める
Socket.SendText(MP_ACCEPT);
fsRecv:=TFileStream.Create(SaveDialog1.FileName,fmCreate);
終わり
else Socket.SendText(MP_REFUSE+'die');
終わり;
MP_FILEPROPERTY:開始
// StrToInt(Copy(sTemp,2,Length(sTemp))) 回送信するには
//時間の経過表示。 。 。
Socket.SendText(MP_NEXTWILLBEDATA);
終わり;
MP_NEXTWILLBEDATA:開始
Socket.SendText(MP_DATA);
bReadText:=false;
終わり;
MP_END:開始
fsRecv.Free
bReadText:=true;
終わり;
MP_ABORT:開始
fsRecv.Free;
bReadText:=true;
終わり;
MP_CHAT:開始
//チャットメッセージ
終わり;
終了;{ケースの}
終わり
そうでなければ始まる
試す
GetMem(bufRecv,2000);//2000 は >iBYTESEND でなければなりません
Socket.ReceiveBuf(bufRecv^,iRecvLength);
fsRecv.WriteBuffer(bufRecv^,iRecvLength);
ついに
FreeMem(bufRecv,2000);
終わり;{試してみた}
bReadText:=true;
Socket.SendText(MP_NEXTWILLBEDATA);
終わり;
終わり;
クライアントプログラム:
次のコントロールを配置します: edtipAddress、OpenDialog1、btnConnect、btnSendFile、
cs. (TClientソケット)
btnConnect.OnClick(Sender:TObject);
始める
cs.Address:=edtIPAddress.Text;
cs.ポート:=2000;
cs.接続;
終わり;
btnSendFile.OnClick(Sender:TObject);
始める
OpenDialog1.Execute の場合
始める
cs.Socket.SendText(MP_QUERY+OpenDialog1.FileName);//FileSize???