シリアルでのファイル転送

[戻る]
プロスト 2002/07/24(水) 10:09:42
二台のパソコンをシリアルケーブルで接続し、ファイルを転送する方法を教えて下さい。

ファイルの転送は、ファイル自体の転送です。
(”オープン→読み込み→転送”の中身の転送ではありません。)

現状、CreateFile→fopen→fgets→WriteFileで、ファイルの中身は転送できますが、
ファイル自体の転送のやり方がわかりません。

イメージ的には、二台のパソコンをシリアルケーブルで接続しての
ファイルのアップロード,ダウンロードです。


お願いします。

dairygoods 2002/07/24(水) 11:54:01
ファイル自体=ファイルの中身

だと思えるのですが、
ファイル自体の転送とはどんな現象を想定しているのでしょうか?

yas0302 2002/07/24(水) 12:35:25
プロストさん、ファイル自体の転送というより
ファイル名を送信したいということでは
ないのでしょうか?
ファイル名をそのまま送信してやれば、
いいんじゃないですか。


送信に限っての処理なら
------------------------------------------------------
[ 送信側 ]                [ 受信側 ]
------------------------------------------------------
CreateFile()

WriteFileで
 文字列長送信    =======> ファイル名の文字列長を受信
WriteFileで
 ファイル名送信  =======> ファイル名を受信(文字列長分を受信する)

fopen(FileName)
fgets()
WriteFile()      =======> ファイルの中身を受信
   :
   :
   :
fclose()

CloseHandle()


アップロード,ダウンロードどちらでも
できるようにするなら、


送信の場合
------------------------------------------------------
[ PC1 ]                [ PC2 ]
------------------------------------------------------

CreateFile()

送信コマンド     =======> 以後、受信処理を行う

WriteFileで
 文字列長送信    =======> ファイル名の文字列長を受信
WriteFileで
 ファイル名送信  =======> ファイル名を受信(文字列長分を受信する)

fopen(FileName)
fgets()
WriteFile()      =======> ファイルの中身を受信
   :
   :
   :
fclose()

CloseHandle()


受信の場合
------------------------------------------------------
[ PC1 ]                [ PC2 ]
------------------------------------------------------

CreateFile()

ファイル要求コマンド ===> 以後、送信処理を行う

WriteFileで
 文字列長送信    =======> ファイル名の文字列長を受信
WriteFileで
 ファイル名送信  =======> ファイル名を受信(文字列長分を受信する)

fopen(FileName)           fopen(FileName)
                          fgets()
受信            <=======  WriteFile() ファイルの中身を送信
   :                         :
   :                         :
fclose()                  fclose()

CloseHandle()



ファイル送信コマンドとファイル要求コマンドは
適当に決めてください。

プロスト 2002/07/24(水) 18:13:03
dairygoodsさん,yas0302さん

レスありがとうございます。


●dairygoodsさん

ファイル自体の転送とは、以下のような事を想定しています。
(イメージ的には、ハイパーターミナルでのファイル送信です。)

(例)
1.パソコンA⇔パソコンBをシリアルケーブルで接続します。
2.パソコンAにあるファイル(???.exe)をパソコンBに転送する。
3.転送先のパソコンBで、ファイル(???.exe)を実行する。


●yas0302さん
この方法は、転送元と同じ名前のファイルを転送先で作成して、
中身を書き込んでいるんですよね?
拡張子がexe等のファイルでも、できるのでしょうか?

拡張子がexe等のファイルを送受信する時、WriteFileやReadFileの
バッファやレングスをどう指定して良いのかわかりません。


ご教授お願いします。

yas0302 2002/07/25(木) 00:20:52
> この方法は、転送元と同じ名前のファイルを転送先で作成して、
> 中身を書き込んでいるんですよね?

そのとおりです。

> 拡張子がexe等のファイルでも、できるのでしょうか?

だめでしょうね。

> 拡張子がexe等のファイルを送受信する時、WriteFileやReadFileの
> バッファやレングスをどう指定して良いのかわかりません。

ファイルサイズは、
_filelength()
CFile::GetLength()
fseek() + ftell() など、好きなものを使って求めてください。

送信の場合
------------------------------------------------------
[ PC1 ]                [ PC2 ]
------------------------------------------------------

CreateFile()

送信コマンド     =======> 以後、受信処理を行う

WriteFileで
 文字列長送信    =======> ファイル名の文字列長を受信
WriteFileで
 ファイル名送信  =======> ファイル名を受信(文字列長分を受信する)

ファイルサイズ取得

ファイルサイズ送信 ====> Length

ファイル読み込み

ファイルの中身を送信 ===> Length 文 ReadFile() する

                          ファイルに書込み

CloseHandle()


受信の場合
------------------------------------------------------
[ PC1 ]                [ PC2 ]
------------------------------------------------------

CreateFile()

ファイル要求コマンド ===> 以後、送信処理を行う

WriteFileで
 文字列長送信    =======> ファイル名の文字列長を受信
WriteFileで
 ファイル名送信  =======> ファイル名を受信(文字列長分を受信する)

                          ファイルサイズ取得

Length          <=======  ファイルサイズ送信

                          ファイル読み込み

Length 文 ReadFile() する <=== ファイルの中身を送信

ファイルに書込み

CloseHandle()



(※注意1)
WriteFile() でファイルサイズ分のデータを一括で
送信はできません。
細かく分割して送信してください。

(※注意2)
fopen() を使うのでしたら、常にバイナリモードで
オープンしてください。
バイナリモードであれば、テキストファイルか否かと
いうことを気にしなくてもいいです。
そのかわり fgets() でなく fread() を使ってください。

プロスト 2002/07/25(木) 14:55:53
yas0302さん

ご教授ありがとうございます。


教えていただいた方法でやってみます。

結果は、後日に報告させていただきます。

プロスト 2002/07/27(土) 16:06:02
とりあえず、ファイルの転送部分のみを作成し、動作させてみました。

転送したファイル(〜.exe)を実行させたところ、正常に動作しませんでした。
実行させると、MS−DOSになり、”This program cannot be run in DOS mode.”
と表示されました。

WriteFile,ReadFileは、一文字づつ行っています。

うまく動作しない理由がわかりません・・・

yas0302 2002/07/28(日) 20:00:34
同じファイルが出来上がってますか?(できていないのでしょうね)
比較してみては、どうでしょう。

(1).まず、ファイルサイズが同じであるか?
(2).ファイルの中身は同じか?

(2)については、コマンドプロンプトで  fc /B file1 file2  とやれば、
違いが表示されます。

ReadFile() した時の、読み込みデータサイズをきちんと確認していますか?
「WriteFile,ReadFileは、一文字づつ行っています。」ということですが、

例えば、
 res = ReadFile(hFile,lpBuffer,1,&dwRead,NULL );

このように書いていたとして、res が0の場合か、dwRead が1でない場合は、
読みとれていませんので、再度読みなおすことが必要です。

プロスト 2002/07/30(火) 10:34:09
お手数をおかけしております。

途中報告です。

●送信したファイルと受信したファイルのサイズをプロパティで比較したところ、
 以下のようになっていました。

 ・送信したファイル    : サイズ 48.0KB (49,152バイト) 49,152バイト使用
 ・受信で作成したファイル : サイズ 39.6KB (40,590バイト) 49,152バイト使用

●”fc /B file1 file2”で、ファイルの内容を比較したところ、左右で数値が違って
 いました。  

ご指摘の通り、同じファイルになっていませんでした。


受信は、以下のようなやり方をしています。

1.タイマーで周期的に受信バッファ中のバイト数を取得。(ClearCommError)
2.受信バッファ中にデータがあるかどうかを確認。 (COMSTATのcbInQue)
3.データがあれば、一文字ずつ書き込む。


確認のため、WriteFileの送信数とReadFileの受信数(書き込み数)を表示させてみたところ、
49,152で同じでした。
ただ、送信するファイルと受信で作成したファイルのファイルポジション(ファイルの大きさ)
を表示させてみたところ、違いがありました。
ファイルポジションは、送信するファイルが49,152で、受信で作成したファイルが49,256
でした。
なぜ、そうなっているのかは、わかりませんが・・・。

yas0302 2002/07/30(火) 11:13:00
まず、

> ・送信したファイル    : サイズ 48.0KB (49,152バイト) 49,152バイト使用
> ・受信で作成したファイル : サイズ 39.6KB (40,590バイト) 49,152バイト使用

ということですので、実際のファイルサイズは、
送信側、49,152バイト と 受信側 40,590バイト であり、
完全に受信できていないことがわかります。
と、いうことは同じファイルにはなっていないということです。
考えられることは、取りこぼしが発生しているということです。

> 1.タイマーで周期的に受信バッファ中のバイト数を取得。(ClearCommError)
> 2.受信バッファ中にデータがあるかどうかを確認。 (COMSTATのcbInQue)
> 3.データがあれば、一文字ずつ書き込む。


1の「タイマーで周期的に・・・」ですが、通信速度とタイマのインターバルの
関係がどうなっているのかよくわかりませんが、受信バッファがあふれる前に
タイマ処理できないと取りこぼしてしまいます。
他のタスクや、メインの処理がどうなっているかもわかりませんが、
タイマは指定した周期で必ず処理されるとは、思わない方がいいですよ。


> データがあれば、一文字ずつ書き込む。

ですが、cbInQue 分全部読み込めばいいと思いますが。

データを取りこぼしている場合は、通信速度を下げてみると
状況がかわると思います。

また、フロー制御していない場合は、フロー制御するように
変更してみてはどうでしょう。

プロスト 2002/08/01(木) 10:02:05
[[解決]]
お手数をおかけしました。

原因は、受信側のファイルをバイナリーモードで作成していませんでした。(汗)


> ですが、cbInQue 分全部読み込めばいいと思いますが。
>
 書き方がまぎらわしかったです。
 確認した時に受信データ(cbInQue)があれば、一文字づつcbInQue分
 だけ書き込みます。


とりあえず、ファイルの転送部分は、動作する事が確認できました。
あとは、電文の送受信部分を作成し、やりとりしながら転送できるように
しようと思います。

今まで色々とご教授していただきありがとうございました。

古いスレッドには追加発言できません。