• ベストアンサー

ソケットプログラミングについて

前回、ここで質問しましたが質問内容がきちんと記述できていなかったので、もう一度質問させていただきます。 [行いたいこと(概要)] PC1(送信端末)に保存されているファイル(jpeg,mpegファイル等)をUDPを使ってPC2(受信端末)へ送信し、PC2側でファイルを開くということです。 [現在、試していること] インターネットや本でもエコープログラミングしかサンプルプログラムがなく、実際どのようにすればよいか分かっていない状況です。以下に、プログラム内容を示します。 PC1(送信端末側) //ファイル名を入力し、ファイルをバイナリ形式で読み込み、sendto関数を用いて送信する。 FILE *fp; printf("送信ファイル名を入力:"); scanf("%s",&fname); if((fp = fopen(fname,"rb")) == NULL){ fprintf(stdout,"ファイルを開く際にエラーが発生しました\n"); exit(1); } while(!feof(fp)){    data = fgetc(fp)    sendto関数を用いて送信する } PC2(受信端末側) //ファイルポインタを用いて、受信ファイル名を記入しバイナリ形式で書き込む。while文は無限ループとし、PC1からのパケットを常時受け取る。 FILE *fp; printf("受信ファイル名を入力:"); scanf("%s",&fname); if((fp = fopen(fname,"wb")) == NULL){ fprintf(stdout,"ファイルを開く際にエラーが発生しました\n"); exit(1); } while(1){    receive関数を用いて受信する。 } 上記に示す様に作ろうと思っているのですが、実際に可能なのでしょうか? ソケットは、Windowsソケット、Linuxソケットどちらでもかまいませんので、よろしければサンプルプログラムも教えていただけないでしょうか? よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.7

きついことを言うようですが… ネットワーク関連のプログラミング、しかもUDPなんていうキツイ仕様を使うには修行が足り無すぎるようです。 まず、1024バイトずつバッファリングしながらローカルでファイルコピーするプログラムをつくりましょう。 buf = fgetc(fp); sendto(sock, (char*)buf, 1024, 0, (struct sockaddr *)&addr, sizeof(addr)); ファイルからデータを1024バイトづつ読む方法はわかってますか? ファイル長が1024の倍数でない場合、残った中途半端な大きさのデータのデータ長を取得する方法がわかりますか? while(1){ recvfrom(sock, buf,1024, 0,NULL,NULL); } 受信したデータをファイルに書いてません。 1024バイトに満たないデータを受け取っても、何バイト受信したか確認してません。 受信側が途中でプログラムを終わっても、送信側に教えてないし。 送信側も、受信側の都合を聞かずに送りつけてるだけだし… テクニックではなく、思慮が足りません。 通信エラーにも対応してないし。

bird_2005
質問者

お礼

>ファイルからデータを1024バイトづつ読む方法>はわかってますか? >ファイル長が1024の倍数でない場合、残った中>途半端な大きさのデータのデータ長を取得する方法>がわかりますか? 分かりません・・・・ もう少し勉強してから、掲示板に分からないことを記載するべきだと言うことを、今、痛感しています。 丁寧なご指摘ありがとうございます。

その他の回答 (7)

  • ency
  • ベストアンサー率39% (93/238)
回答No.8

ファイル転送のアプリケーションを作りたいのであれば、すでに回答にもありますが TCPソケットで作るべきです。 「まず UDPソケットを使って…」というのは、根本的に勘違いをしているような気がします。 アプリケーションプロトコルを自作する場合、TCP を使うよりも UDP を使うほうが難しいと思います。 理由は、UDP では何もしてくれないから必要な機能をすべて実装しなければならないからです。 TCP ならば、パケットが届いたのかどうかを含めて、届いていなければ再送してくれたり、順番どおりに並べ替えてくれたりしてくれるので、アプリケーションを作るほうからすれば、余計なことを考える必要がありません。 それこそ、ファイルのようにソケットに Write し、ソケットから Read すれば良いわけです。 # ま、TCP の場合、クライアントとサーバで処理でオープンする処理が # 異なるわけですが、それはまた別の話で。。。 それとも、単に UDP を勉強したから「ファイル転送のアプリケーションを作ってみたい」と思っただけでしょうか。 もしそうなのであれば、まずは数バイトのデータを UDPソケットを使って送受信するプログラムを作るところから始めましょう。 そして必要に応じて大きなファイルを送受信できるように、機能拡張していくと。。。 # 途中で TCP に切り替えるべきだとは思いますが。。。 こんなアドバイスでいかがでしょうか。

bird_2005
質問者

お礼

書き込みありがとうございます。 お返事が遅れてしまいすみませんでした。

  • uyama33
  • ベストアンサー率30% (137/450)
回答No.6

本を紹介します。 WinSock2.0 プログラミング 出版社:ソフトバンク パブリッシング株式会社 著者:Lewis Napper 500ページくらいの本で ソケットについて丁寧に書いてあります。  私はこれを参考にして メーラーを作りました。

bird_2005
質問者

お礼

書き込みありがとうございます。 参考にさせていただきます。 「猫でもわかるネットワークプログラミング」という本も分かりやすそう?でこちらも参考にしたいと思っています。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.5

while(!feof(fp)){ buf = fgetc(fp); sendto(sock, (char*)buf, 1024, 0, (struct sockaddr *)&addr, sizeof(addr)); } 1バイトしか読んでないのに1024バイトとして送るんですか? bufは読み込んだ1バイトのデータが入ってるはずですが、それを(char *)にキャストしてるので非情に危険です。

bird_2005
質問者

補足

>>1バイトしか読んでないのに1024バイトとして送るんですか? Cのテキスト上に、(バイナリ)ファイルコピープログラムが記載されていたため、これで出来るのではないかと思いやってみたしだいです。 実際に、試してみたいこととして1024バイトずつ送信したいのですが・・・何か良い方法はありませんか?

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.4

そのプログラムだと 送信データ 1、2、3、4、5 受信データ 2、3、3,1、5(1が遅延到達、3が重複到達、4が欠落) この場合に対応できません。 ※パケットという単語はココで使うのは適当ではありません UDPの場合送信単位ごとに通信経路が変る可能性があります。 先ほども書きましたが… 順番は期待通りにならない、届かないことがある、2回以上届くこともある この3つを考えて送受信の約束事(プロトコル)を設計する必要があります。 例えば… 1.送信側---送信データ数--->受信側 2.送信側<--データ数受信OK--受信側 3.受信側でデータ数分のバッファを用意 4.送信側---データを番号付きで送信--->受信側 5.受信側で受信したデータを、番号にマッチするバッファに保存 6.データ数分4~5くり返し 7.送信側---最終データ送信完了-->受信側 8.受信側で、不足しているデータを検出して、番号リストを作る 9.送信側<---不足データ番号群---受信側 10・送信側---不足データの再送--->受信側 11.10をくり返し 12・送信側---再送完了--->受信側 13・受信側で再び不足データ検出 14.送信側<---完了or失敗報告----受信側 大雑把な流れとしてこの程度は必要です。 実際にはこれでも遅延到達データの処理や、制御データ(送信データ数、完了/失敗報告)の遅延/欠落が起こった場合に対応できていないので使い物にはなりません。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.3

まず、UDPの基本的なことを理解してください。 ・1度に送ることができるデータはせいぜい数キロバイト ・分割送信したデータは期待通りの順番で届くという保証が無い ・送信データが通信経路上で欠落するとがある ・通信経路がルーティングされていて複数の経路を取りえる場合、同一のデータが複数の経路から重複して到達してしまうことがある どうしてもUDPで送りたいなら大雑把な流れとして ・送信側でデータを分割して、シーケンス番号を付けて送信 ・受信側で受信したデータを、シーケンス番号をもとに組み立てるが、欠損部分があれば再送を要求 ・送信側は再送要求を受けると、該当部分を再送 ・送受信の互いに満足したら(諦めがついたら?)通信終了 こんな感じでしょうか。 もちろん、細かい約束事の取り決めが必要です。

bird_2005
質問者

補足

書き込みありがとうございます。 UDPの機能は、だいたい分かっているのですが、プログラミングのスキルが追い付いておりません・・・が勉強していきたいと思っています。 試しにUDPのプログラムをサンプルを参考にしながら作ってみたのですが、案の定、送信側から受信側へファイルが送信されていません。以下にプログラムを示します。 以下のプログラムは、受信側を立ち上げておいてから送信側を起動します。 送信側と受信側プログラムの一部を記述します。 [送信側] printf("読み込みファイル名を入力:"); scanf("%s",&fname); if((fp = fopen(fname,"rb")) == NULL){ fprintf(stdout,"ファイルを開く際にエラーが発生しました\n"); exit(1); } while(!feof(fp)){ buf = fgetc(fp); sendto(sock, (char*)buf, 1024, 0, (struct sockaddr *)&addr, sizeof(addr)); } fclose(fp); closesocket(sock); [受信側] printf("書き込みファイル名を入力:"); scanf("%s",&fname); if((fp = fopen(fname,"wb")) == NULL){ fprintf(stdout,"ファイルを開く際にエラーが発生しました\n"); exit(1); } memset(buf, 0, sizeof(buf)); printf("接続を待ち\nクライアントプログラムを動かしてください\n"); while(1){ recvfrom(sock, buf,1024, 0,NULL,NULL); } fclose(fp); closesocket(sock); 上記プログラムは、ファイルポインタを使用してファイルを指定し、1024バイトずつUDPで送信。受信側は無限ループとして送信側からのパケットを常時受信する。と言う風に作ったつもりです。 シーケンス番号等は付けておりません。 よろしくお願いします。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

今回のケースでは、UDPによる転送は無理があります。1回の送信で送信出来るサイズは、限られていますので、ファイル(たぶん1Mバイトはあるでしょう)を、1回の送信では、送れません。 従って、TCP/IPの手順で送ることになります。 TCP/IPの簡単なサンプルが表示されたURLを示しますので、そちらを参考にして下さい。

参考URL:
http://www.bmc.riken.go.jp/~onishi/programming/tcp_linux.html
bird_2005
質問者

お礼

書き込みありがとうございます。 示していただきました、サンプルを参考に作っていきたいと思っています。 これからも、掲示板に書き込みした際には、よろしくお願いします。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

なんでUDPを使うのかな。 UDPはシーケンスチェックも到着確認もないので、そういう部分はアプリケーションでカバーしなければならない。TCPの方が簡単だと思うが。 特に画像ファイルのような大きいデータは1パケットに入りきらないので複数パケットの到着順管理も必要で、回答に簡単なサンプルをかけるようなものでもない。 どうしてもUDPでのファイル転送が必要なら確かtftpコマンドがUDPを使っていたと思うので、このソースでも読むのが手っ取り早いでしょう。

bird_2005
質問者

お礼

書き込みありがとうございます。 UDPの機能については、だいたい知っているのですが、プログラミングが苦手でして・・・・。 まずは、UDPを使って練習をしようと思っています。

関連するQ&A

専門家に質問してみよう