- ベストアンサー
Winsockを利用した単純なファイル送信プログラムについて
- Winsockを使用したUDPを利用した単純なファイル送信プログラムの概要と内容について
- 送信側からのファイル送信が正常に行われない原因を特定するため、WinsockのUDPを用いた単純なファイル送信プログラムを作成したいと考えています
- 詳細なプログラムの内容としては、送信側ではファイルポインタを使用してファイルをオープンし、fread関数とsendto関数を用いて1024バイトずつ送信します。一方、受信側では無限ループ内でrecvfrom関数とfwrite関数を用いて送信側からのデータを受信し、ファイルに書き込みます。
- みんなの回答 (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の値を印字してみては、いかがですか。 そうすれば、何文字読めているかも確認できます。
その他の回答 (6)
- tatsu99
- ベストアンサー率52% (391/751)
>ワイヤレス環境下であり、かつUDPを使用しているため、パケットが送信側から受信側へ行く途中でロスしてしまっているのだと思っています・・・・。 >大変勉強になっているのですが、ロス率をできるだけ回避する方法とかあるのでしょうか? UDPはもともとロスすることを前提としたプロトコルなので、やむを得ないと考えます。これを避けるには、TCP/IPにより、送受信を行う方法しかありません。 UPDを使用し、かつロスしない仕組みをアプリケーションで作るなら、以下のようになります。(1つの例として) 1)送り側は、データの先頭にデータの番号を付加して送ります。データの番号は、int型整数(4バイト)が、妥当でしょう。これを1からの連番で、送ります。 2)受信側は、この番号を監視します。従って、純粋なデータは、受信したものから、この番号を削除したものになります。 3)受信側では、データを受信する都度、受信した証として、この番号を送信元へ送ります。 4)送信側は、自分が送った番号が、受信側から戻ったことを確認して、次のデータを送ります。 上記のように、UDPでデータのロストを防ぐためには、大変な労力が発生します。もともと、ロストしても良い場合に、UDPを使用します。従って、他の方も言われてますように、TCP/IPで送信を行うのが、最も現実的な解決の方法になります。
お礼
いろいろ教えてくださり、ありがとうございました。 大変勉強になりました。 これからもプログラミング、ネットワークの学習に精を出していきたいと思っています。 また質問したときには、よろしくお願いします。
- tatsu99
- ベストアンサー率52% (391/751)
>3Mバイト程度のmpegファイルまたは、150Kバイト程度のjpegファイルを送信してみたところ、送信はできていると思うのですが、うまく受信できません。 どのように、うまくできていないのですか? 1)「データ受信しました」は、受信側で表示されましたか? 2)「データ受信しました」は、送信側で表示されましたか?(データ送信しましたの間違い?) 3)受信側でファイルに書いた内容と、送信側のファイルの内容は一致していますか?
補足
書き込みありがとうございます。 <引用文> 1)「データ受信しました」は、受信側で表示されましたか? 2)「データ受信しました」は、送信側で表示されましたか?(データ送信しましたの間違い?) 3)受信側でファイルに書いた内容と、送信側のファイルの内容は一致していますか? 申し訳ありません。きちんと、送信データを受信することができました。受信側の「データ受信しました」もきちんと表示されました。 ありがとうございました。 実は、今まで、一台の端末で送信側と受信側のプログラムを走らせてデータ送信と受信を確かめていました。 さきほど端末2台を用いて、ワイヤレス環境下でのアドホック通信を試みたところ、3Mバイトのmpegファイルを送信したところ、受信側では1Mバイト程度のファイルになっていました。また、jpegファイルのファイル容量によって、受信側の「データ受信しました」が表示されず「Ctrl + C」にて強制終了しています。 ワイヤレス環境下であり、かつUDPを使用しているため、パケットが送信側から受信側へ行く途中でロスしてしまっているのだと思っています・・・・。 大変勉強になっているのですが、ロス率をできるだけ回避する方法とかあるのでしょうか? たびたびすみません。 よろしくおねがいします。
- tatsu99
- ベストアンサー率52% (391/751)
受信側ですが、 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); よい方法がありましたら、教えていただけないでしょうか?よろしくお願いします。
- rinkun
- ベストアンサー率44% (706/1571)
あなたはネットワーク以前にC言語の文法を一からやり直した方が良い。 > while(n = fread(send_buf,1,1024,fp) != -1){ この行を実行したとき、読込みに成功すると何文字読み込んだかによらずnは1になる。何故そうなるのかは自分で良く文を読み返して確認し理解すること。
お礼
書き込みありがとうございます。 また、よろしくお願いします。
- xcrOSgS2wY
- ベストアンサー率50% (1006/1985)
では、ファイルを読み込んで送信するのを止めて、単純にsendtoを行うだけにしてテストしてみてください。1回のsendtoだけなら成功しますか? ・・・というふうに、単純なものから順番に調べていくのが、普通の調べ方です。
- xcrOSgS2wY
- ベストアンサー率50% (1006/1985)
1. どのように、うまく受信できていないのですか。ある程度のデータは受信側に届いているのですか、それとも何も届いていないのですか。送信側は正常終了するのですか、何かエラーが発生するのですか。 2. 一度に送信するデータの量を128バイトに減らすと、状況はどう変わりますか。
補足
書き込みありがとうございます。 >1. どのように、うまく受信できていないのですか。 ある程度のデータは受信側に届いているのですか、それとも何も届いていないのですか。送信側は正常終了するのですか、何かエラーが発生するのですか。 「hoge」と記述したテキストファイルを送ってみたところ、受信側では、「hoge」の頭文字である「h」がたくさん表示されます。 送信側は、while(n = fread(send_buf,1,128,fp) != -1)から抜けると「データ送信しました」と表示するようにしましたが、表示されません。そこで「ctrl + C」で強制的に終了しています。また、受信側も同様に強制終了しています。 2.128バイトに減らしても1の内容と変わりませんでした。 よろしくお願いします。
補足
書き込みありがとうございます。 <引用文> 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; と記述したのですが、エラーのためできませんでした。 よろしくお願いします。