アプリ版:「スタンプのみでお礼する」機能のリリースについて

こんばんは。
何度もこの掲示板を利用させていただいている者です。

WinsockのUDPを用いて簡単なファイル送信プログラムを作っています。UDPを使わずに、TCPを使用したほうが良いのでは?とのご指摘をいただきましたが、まずは、UDPを利用した単純なファイル送信プログラムを作ってみたいと思っています。

しかし、送信側から受信側へファイルがうまく受信できていません。もしかしたら、送信側自体がきちんと送信できていないのかもしれません。

以下にそのプログラムの概要と内容を示します。

[概要]
送信側→受信側にUDPを用いて、送信側にあるjpegまたはmpegファイルを送信し、受信側でファイルを開く。

[プログラム概要]
・送信側
ファイルポインタを用いてファイルオープン
fread関数とsendto関数を用いて1024バイトずつ送信

・受信側
ファイルポインタを用いてファイルオープン
whileの無限ループ内に、recvfrom関数とfwrite関数を用いて送信側からのデータを受信

[プログラムの内容]
・送信側
printf("読み込み用ファイルを入力して下さい:");
scanf("%s",fname);
if((fp = fopen(fname,"rb")) == NULL){
printf("入力ファイルをオープンできない。\n");
exit(1);
}

char send_buf[1025];
int n;

while(n = fread(send_buf,1,1024,fp) != -1){
sendto(theSocket,send_buf,n,0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr));
}

・受信側
char Recv_buf[1025];
char size;
SOCKADDR_IN saClient;

while(1){
size = recvfrom(theSocket,Recv_buf,1024,0,(LPSOCKADDR)&saClient,&nLen);
fwrite(Recv_buf,size,1,fp);
}

ご指摘またはご教授をいただけたらと思います。

よろしくお願いします。

A 回答 (7件)

while(n = fread(send_buf,1,1024,fp) != -1){



ですが、freadはファイル終了時、0を返します。
-1が返ることはありません。
while((n = fread(send_buf,1,1024,fp)) != 0){
としてください。
#3のかたの指摘は、自分で考えるとして、
とりあえず、上記のようにしてください。
また、
while()}
sendto()...
}
のなかで、nの値を印字してみては、いかがですか。
そうすれば、何文字読めているかも確認できます。

この回答への補足

書き込みありがとうございます。

<引用文>
while()}
sendto()...
}
のなかで、nの値を印字してみては、いかがですか。
そうすれば、何文字読めているかも確認できます。

-------------------------------------------------
そこで以下のように記述してみました。
[送信側]
char send_buf[1025];
char send[4] = "end";
int n;
int Num_n = 0;

while((n = fread(send_buf,1,1024,fp)) != 0){
Num_n++;
printf("n:%s\t",send_buf);
sendto(theSocket,send_buf,n,0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr));
}
printf("nの数:%d\n",Num_n);
sendto(theSocket,send,strlen("end"),0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr));

[受信側]
char Recv_buf[1025];
char size;
SOCKADDR_IN saClient;

while(1){
size = recvfrom(theSocket,Recv_buf,1024,0,(LPSOCKADDR)&saClient,&nLen);
fwrite(Recv_buf,size,1,fp);

//エラーではじかれる部分
if(!strcmp(size,"end")) break;
}

printf("ファイル受信完了\n");

送信側PCに、
printf("n:%s\t",send_buf)
にて、画面出力させたところテキストファイル内の文字列が表示されました。

次の問題なのですが、
送信側のwhileループから抜けた時点で「end」を送信し、受信側で「end」を受信したら無限ループから抜けるようにしてみたのですが、受信側の記述方法が分かりません。

上記の受信側プログラムに
if(!strcmp(size,"end")) break;
と記述したのですが、エラーのためできませんでした。

よろしくお願いします。

補足日時:2005/11/10 17:05
    • good
    • 0

>ワイヤレス環境下であり、かつUDPを使用しているため、パケットが送信側から受信側へ行く途中でロスしてしまっているのだと思っています・・・・。



>大変勉強になっているのですが、ロス率をできるだけ回避する方法とかあるのでしょうか?


UDPはもともとロスすることを前提としたプロトコルなので、やむを得ないと考えます。これを避けるには、TCP/IPにより、送受信を行う方法しかありません。

UPDを使用し、かつロスしない仕組みをアプリケーションで作るなら、以下のようになります。(1つの例として)
1)送り側は、データの先頭にデータの番号を付加して送ります。データの番号は、int型整数(4バイト)が、妥当でしょう。これを1からの連番で、送ります。
2)受信側は、この番号を監視します。従って、純粋なデータは、受信したものから、この番号を削除したものになります。
3)受信側では、データを受信する都度、受信した証として、この番号を送信元へ送ります。
4)送信側は、自分が送った番号が、受信側から戻ったことを確認して、次のデータを送ります。


上記のように、UDPでデータのロストを防ぐためには、大変な労力が発生します。もともと、ロストしても良い場合に、UDPを使用します。従って、他の方も言われてますように、TCP/IPで送信を行うのが、最も現実的な解決の方法になります。
    • good
    • 0
この回答へのお礼

いろいろ教えてくださり、ありがとうございました。
大変勉強になりました。
これからもプログラミング、ネットワークの学習に精を出していきたいと思っています。

また質問したときには、よろしくお願いします。

お礼日時:2005/11/11 14:21

>3Mバイト程度のmpegファイルまたは、150Kバイト程度のjpegファイルを送信してみたところ、送信はできていると思うのですが、うまく受信できません。



どのように、うまくできていないのですか?
1)「データ受信しました」は、受信側で表示されましたか?
2)「データ受信しました」は、送信側で表示されましたか?(データ送信しましたの間違い?)
3)受信側でファイルに書いた内容と、送信側のファイルの内容は一致していますか?

この回答への補足

書き込みありがとうございます。

<引用文>
1)「データ受信しました」は、受信側で表示されましたか?
2)「データ受信しました」は、送信側で表示されましたか?(データ送信しましたの間違い?)
3)受信側でファイルに書いた内容と、送信側のファイルの内容は一致していますか?


申し訳ありません。きちんと、送信データを受信することができました。受信側の「データ受信しました」もきちんと表示されました。

ありがとうございました。

実は、今まで、一台の端末で送信側と受信側のプログラムを走らせてデータ送信と受信を確かめていました。

さきほど端末2台を用いて、ワイヤレス環境下でのアドホック通信を試みたところ、3Mバイトのmpegファイルを送信したところ、受信側では1Mバイト程度のファイルになっていました。また、jpegファイルのファイル容量によって、受信側の「データ受信しました」が表示されず「Ctrl + C」にて強制終了しています。

ワイヤレス環境下であり、かつUDPを使用しているため、パケットが送信側から受信側へ行く途中でロスしてしまっているのだと思っています・・・・。

大変勉強になっているのですが、ロス率をできるだけ回避する方法とかあるのでしょうか?

たびたびすみません。
よろしくおねがいします。

補足日時:2005/11/11 12:33
    • good
    • 0

受信側ですが、


char size;を
int size;にしてください。char型では127バイトまでしか、対応できません。(300バイトがくると、動作がおかしくなります)

問題の場所を、以下のようにしてください。

if (size == 3){
if (memcmp(Recv_buf,"end",3) == 0) break;
}

とします。
これは、受信したサイズが3バイトかつ、受信した文字が
"end"ならbreakするという意味です。
recvfromの戻り値は、受信したデータではなく、受信したデータのサイズですから、その点を間違えないでください。

この回答への補足

書き込みありがとうございます。

ご提示して下さいました、プログラムを以下の場所に挿入したところ、テキストファイルを送信側から受信側へと送信することができました。

ありがとうございます。

また質問なのですが、
3Mバイト程度のmpegファイルまたは、150Kバイト程度のjpegファイルを送信してみたところ、送信はできていると思うのですが、うまく受信できません。ファイルの最後を意味するために付け加えた「end」では、mpegやjpegファイルに対しては効果がないのでしょうか?

[送信側]
char send_buf[1025];
char send[4];
int n;
int Num_n = 0;

strcpy(send, "end");
while((n = fread(send_buf,1,1024,fp)) != 0){
Num_n++;
printf("n:%dバイト\t",n);
sendto(theSocket,send_buf,n,0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr));
}
printf("nの数:%d\n",Num_n);
sendto(theSocket,send,strlen(send),0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr));
printf("データ受信しました\n");
fclose(fp);
closesocket(theSocket);

[受信側]
char Recv_buf[1025];
int size;
SOCKADDR_IN saClient;

while(1){
size = recvfrom(theSocket,Recv_buf,1024,0,(LPSOCKADDR)&saClient,&nLen);
fwrite(Recv_buf,size,1,fp);
if (size == 3){
if (memcmp(Recv_buf,"end",3) == 0) break;
}

}

printf("データ受信しました\n");
fclose(fp);
closesocket(theSocket);

よい方法がありましたら、教えていただけないでしょうか?よろしくお願いします。

補足日時:2005/11/10 23:48
    • good
    • 0

あなたはネットワーク以前にC言語の文法を一からやり直した方が良い。



> while(n = fread(send_buf,1,1024,fp) != -1){

この行を実行したとき、読込みに成功すると何文字読み込んだかによらずnは1になる。何故そうなるのかは自分で良く文を読み返して確認し理解すること。
    • good
    • 0
この回答へのお礼

書き込みありがとうございます。
また、よろしくお願いします。

お礼日時:2005/11/10 15:09

では、ファイルを読み込んで送信するのを止めて、単純にsendtoを行うだけにしてテストしてみてください。

1回のsendtoだけなら成功しますか?

・・・というふうに、単純なものから順番に調べていくのが、普通の調べ方です。
    • good
    • 0

1. どのように、うまく受信できていないのですか。

ある程度のデータは受信側に届いているのですか、それとも何も届いていないのですか。送信側は正常終了するのですか、何かエラーが発生するのですか。

2. 一度に送信するデータの量を128バイトに減らすと、状況はどう変わりますか。

この回答への補足

書き込みありがとうございます。

>1. どのように、うまく受信できていないのですか。 ある程度のデータは受信側に届いているのですか、それとも何も届いていないのですか。送信側は正常終了するのですか、何かエラーが発生するのですか。

「hoge」と記述したテキストファイルを送ってみたところ、受信側では、「hoge」の頭文字である「h」がたくさん表示されます。

送信側は、while(n = fread(send_buf,1,128,fp) != -1)から抜けると「データ送信しました」と表示するようにしましたが、表示されません。そこで「ctrl + C」で強制的に終了しています。また、受信側も同様に強制終了しています。

2.128バイトに減らしても1の内容と変わりませんでした。

よろしくお願いします。

補足日時:2005/11/09 19:50
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!