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

こんばんわ。

A端末(送信端末)→B端末(受信端末)というように、A端末から複数パケットを送信し、B端末でパケットを受信するというプログラムをUDPを用いて作成しています。

[実装したいこと]
・A端末において各パケットに対して、通番(TCPのシーケンス番号)のよ うなものを挿入し、パケットを送出。
・B端末で、どの通番を持つパケットを受信することができたか?を確 認したい。
と思っています。

そこで、上記をふまえ以下のようなプログラムを作成しました。

[A端末(送信側)]
//main
main(int argc ,char *argv[]){
  UDPSending(s_port,szServer);
}

//whileループにてsend_packet関数を何回も呼び出す。packet_Num変数よりカウントアップ。
UDPSending(unsigned short s_port,char *szServer){
 int packet_Num = 1; 

 while((n = fread(send_Buf,1,SEND_DATA_SIZE,fp)) != 0) {
   send_packet(packet_Num, s_port, szServer, send_Buf, n);
   packet_Num++;
 }
}

//sprintf関数を使用し各パケットに通番を付加
send_packet(int packet_Num, unsigned short s_port, char *szServer, char *send_Buf, int n){
  char send_Buff[1500];
  //配列初期化
  memset(send_Buff,'\0',sizeof(send_Buff));
  //send_Bufに文字列を付加?
  sprintf(send_Buf+32,"%d\n",packet_Num);
  //send_Bufの内容をsend_Buffへコピー
  memcpy(send_Buff,send_Buf,n);
  UDPDataSend(s_port, szServer, send_Buff, n);
}

//パケット送出
UDPDataSend(unsigned short s_port, char *szServer, char *send_Buff, int n){
  sendto(省略)
}

上記のように、sprintf関数を使用しpacket_Num変数の文字列を挿入することで、送出されるパケットに通番を割り振っていることになるのでしょうか?

よろしくお願い致します。

A 回答 (5件)

こんばんわ。



send_packet(int packet_Num, unsigned short s_port, char *szServer, char *send_Buf, int n){
  char send_Buff[1500];
  //配列初期化
  memset(send_Buff,'\0',sizeof(send_Buff));
  //send_Bufに文字列を付加?
  sprintf(send_Buf+32,"%d\n",packet_Num);★1
  //send_Bufの内容をsend_Buffへコピー
  memcpy(send_Buff,send_Buf,n);★2
  UDPDataSend(s_port, szServer, send_Buff, n);★3
}

★1
send_Buf は 先頭から n 文字まで送信データが入っているのに、33文字目の位置に packet_Num を書き込もうとしています。
この時点で間違いですが、nは可変なので packet_Num を埋め込むなら send_Buf の先頭にするべきでは?
send_Buf+32 つまり send_Buf が指すバッファの33バイト目へ書き込むことを固定指定している理由は何ですか?
送信しようとしているデータのフォーマット(先頭何バイトが何で、何バイト目から何バイト目が何で、、、)を提示いただけませんか?
★2
send_Buff に送信データ+通番 をコピーしようとしているとすれば、第三引数はnではダメですね。
またその場合、packet_Numは%dで書き込んでいるため、1~9なら1文字、10~99なら2文字というように文字数が変わりますから、
%05d のように桁数を固定した上で、n+6バイト(\nの1バイト分を含む)をmemcpyしたほうがいいかもしれません。
★3
UDPDataSendの第四引数もnではなく n + packet_Numのバイト数 となります。

send_packet(int packet_Num, unsigned short s_port, char *szServer, char *send_Buf, int n){
  char send_Buff[1500];
  //配列初期化
  memset(send_Buff,'\0',sizeof(send_Buff));
  //通番を先頭に付加
  sprintf(send_Buff,"%05d\n",packet_Num);
  //send_Bufの内容を後ろにつなげる
  strcat(send_Buff,send_Buf);
  // 送信
  UDPDataSend(s_port, szServer, send_Buff, n+6);
}

試してませんが、考え方のひとつとして参考になればと思います。

この回答への補足

こんばんわ。回答ありがとうございます。
参考にさせていただきます。

>nは可変なので packet_Num を埋め込むなら send_Buf の先頭にす
>るべきでは?

#define SEND_DATA?_SIZE 1024
int n;

while((n = fread(send_Buf,1,SEND_DATA_SIZE,fp)) != 0) {
   send_packet(packet_Num, s_port, szServer, send_Buf, n);
   packet_Num++;
}

と言う様に、fread関数を用いて画像ファイルや動画ファイルを1024バイトずつ(変数nに1024が返される)区切っています。回答を参考にさせていただきます。

>send_Buf+32 つまり send_Buf が指すバッファの33バイト目へ書き込
>むことを固定指定している理由は何ですか?

参考となるテキストのサンプルプログラムを解読し、この様に記述すればうまく行くと思ったしだいです。

>送信しようとしているデータのフォーマット(先頭何バイトが何で、
>何バイト目から何バイト目が何で、、、)を提示いただけませんか?

#define SEND_DATA_SIZE 1024
n = fread(send_Buf,1,SEND_DATA_SIZE,fp)
から、バイナリデータを1024バイトずつ区切っているので、先頭(配列[0])~1024(配列[1023])までがバイナリデータとなると思っています。

よろしくお願いします。

補足日時:2006/10/16 21:59
    • good
    • 0

補足ありがとうございます。


1024バイト単位で送信していることはわかりました。
>sprintf(send_Buf+32,"%d\n",packet_Num);★
ココが謎だったのですが、とあるサンプルがそのように記述してあったということですね。サンプルの正否は私にはわかりませんが、send_Bufの先頭から1024バイトには送信する大事なデータが入っているのに、その33バイト目から(33+packet_Numの桁数)バイト目の値を、packet_Numの値で上書きしてしまうプログラムだということがおわかりになりますか?送信データの先頭や最後尾にpacket_Numを付与するならともかく、データ部分を書き換えてしまっては、正しいデータが送信できないということを指摘しています。

TCPヘッダ、UDPヘッダのフォーマット
http://www.7key.jp/nw/tcpudp.html

ここを御覧いただくとわかるように、UDPヘッダには順序制御がありません。bird0214さんのコードは、上記URLのUDPヘッダ図の「データ」部分の先頭から33バイト目に順序制御用の通番を入れようとしているように見えます。ならば、実際に受信側が意味あるデータとして扱うのは通番で上書きされたところより後の部分で、1~32バイト目には通番以外の何か(そのサンプルではそうしているのでしょう)がセットされているという前提があるのではないでしょうか。
bird0214さんが送信したいデータフォーマットとは具体的にどんなものですか?
私には、1024バイトのうちデータのバイトをD、通番(%5dで5桁の文字列と仮定)が占めるバイトをNと表記した場合、
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDNNNNNDDDDDD.....DDDDDD←1023バイト目
このようなバイナリを送信しようとしているように見えます。受信側ではこれを受信して、先頭から33~37バイト目を通番として読み、38~1023バイト目をデータとして解釈する仕様なのですか?ココ、差し支えなければご返答ください。

逆に質問させていただいていますが、
>上記のように、sprintf関数を使用しpacket_Num変数の文字列を挿入することで、
>送出されるパケットに通番を割り振っていることになるのでしょうか?
という最初のご質問への回答は、Yesです。
通番で送信データの一部が上書きされてしまいますが、パケットごとに通番が埋め込まれることにはなっています。

参考URL:http://www.7key.jp/nw/tcpudp.html

この回答への補足

こんにちは。
返答ありがとうございます。

>send_Bufの先頭から1024バイトには送信する大事なデータが入ってい
>るのに、その33バイト目から(33+packet_Numの桁数)バイト目の値を、>packet_Numの値で上書きしてしまうプログラムだということがおわか
>りになりますか?

>1~32バイト目には通番以外の何か(そのサンプルではそうしているの
>でしょう)がセットされているという前提があるのではないでしょう
>か。

sprintf(send_Buf+32,"%d\n",packet_Num);←このように記述すればできるのではないか?と思っていました。上書きされることは知りませんでしたので大変勉強になりました。おそらく、このサンプルプログラムは、1~32バイト目までに送出パケットに対して、送出時の時刻が挿入してあります。

>bird0214さんが送信したいデータフォーマットとは具体的にどんなも
>のですか?

私は、画像や動画データを1024ばいとずつ送信していきたいと思っています。そこで、1024バイトのうちデータのバイトをD、通番をNとした場合。

NNNNNDDDDDDDDDDDDDDDDDDDDDDDDDDDD.....DDDDDD←1030バイト目
というようにmerutyさんの言うとおり、先頭に通番を挿入し、その後ろに実データを挿入したいと思っています。

しかし、前日に教えていただきましたプログラムを実装しましたので、1024(実データ)+6(通番)=1030バイトずつ送信していることになっています。

また、質問内容の付けたしなのですが・・・
受信側にて受信できた通番を取得したいと思い、以下のようなに記述(受信(1))し、テキストファイルに出力してみたところ、確かに通番が表示されているのですが、それ以外の文字列(文字化けしている)がたくさん表示されてしまいます。

そこで、通番の最後に\0を挿入している?と言うことに気づき受信(2)のように記述したのですが、実行途中でエラーが発生し強制終了してしまいます。

[受信(1)]
char recv_Buf[1500];
int sequence_Num;

sscanf(recv_Buf,"%05d\n",&sequence_Num);
fprintf(fp4,"%s",recv_Buf);

[受信(2)]
char recv_Buf[1500];
int x;
for(x=0;recv_Buf[x] != '\0'; x++){
  fprintf(fp4,"%s",recv_Buf[x]);
}

なにか解決策はありますでしょうか?
よろしくお願いいたします。

補足日時:2006/10/17 13:10
    • good
    • 0
この回答へのお礼

申し訳ありません。

追加質問しました、受信側において取得できたパケットの通番をファイル出力する機能についての質問でしたが、

fprintf(fp,"%c%c%c%c%c\n",recv_Buf[0],recv_Buf[1],recv_Buf[2],recv_Buf[3],recv_Buf[4]);

先頭[0]~[4]までが通番としてあるので、上記のように受信側にて記述したところ、ファイル出力可能となりました。

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

最後に、あと一つ疑問な点として、
私は、merutyさんに教えていただいた方法で、画像や動画ファイルを1024バイトずつ区切り、先頭に6バイト分の通番を付加して、1024(実データ)+6(通番)=1030バイトで送信しています。通番を付加して送信するため、受信側においてファイルを開くことができません。これは当たり前?のことなのでしょうか。

お礼日時:2006/10/17 16:19

補足ありがとうございます。


1024バイト単位で送信していることはわかりました。
>sprintf(send_Buf+32,"%d\n",packet_Num);★
ココが謎だったのですが、とあるサンプルがそのように記述してあったということですね。サンプルの正否は私にはわかりませんが、send_Bufの先頭から1024バイトには送信する大事なデータが入っているのに、その33バイト目から(33+packet_Numの桁数)バイト目の値を、packet_Numの値で上書きしてしまうプログラムだということがおわかりになりますか?送信データの先頭や最後尾にpacket_Numを付与するならともかく、データ部分を書き換えてしまっては、正しいデータが送信できないということを指摘しています。

TCPヘッダ、UDPヘッダのフォーマット
http://www.7key.jp/nw/tcpudp.html

ここを御覧いただくとわかるように、UDPヘッダには順序制御がありません。bird0214さんのコードは、上記URLのUDPヘッダ図の「データ」部分の先頭から33バイト目に順序制御用の通番を入れようとしているように見えます。ならば、実際に受信側が意味あるデータとして扱うのは通番で上書きされたところより後の部分で、1~32バイト目には通番以外の何か(そのサンプルではそうしているのでしょう)がセットされているという前提があるのではないでしょうか。
bird0214さんが送信したいデータフォーマットとは具体的にどんなものですか?
私には、1024バイトのうちデータのバイトをD、通番(%5dで5桁の文字列と仮定)が占めるバイトをNと表記した場合、
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDNNNNNDDDDDD.....DDDDDD←1023バイト目
このようなバイナリを送信しようとしているように見えます。受信側ではこれを受信して、先頭から33~37バイト目を通番として読み、38~1023バイト目をデータとして解釈する仕様なのですか?ココ、差し支えなければご返答ください。

逆に質問させていただいていますが、
>上記のように、sprintf関数を使用しpacket_Num変数の文字列を挿入することで、
>送出されるパケットに通番を割り振っていることになるのでしょうか?
という最初のご質問への回答は、Yesです。
通番で送信データの一部が上書きされてしまいますが、パケットごとに通番が埋め込まれることにはなっています。
    • good
    • 0

すみません。

重複送信してしまったようです。#3は無視してください。以後気をつけます。申し訳ありませんでした。
    • good
    • 0

こんばんわ。


上書きについてご理解いただけて何よりです。
send_Buf は char* つまりポインタであり、ポインタに数値を加算・減算すると「そのポインタが指す変数型のバイト数だけ、ポインタが指し示すアドレスが前進・後退する」というCの仕様により、
send_Buf+32 は 33 バイト目を指すということでした。

>fprintf(fp,"%c%c%c%c%c\n",recv_Buf[0],recv_Buf[1],recv_Buf[2],recv_Buf[3],recv_Buf[4]);

5桁と決まっているのですから、この部分はもっとシンプルな記述ができると思います。余力があれば検討してみてください。

なお、結論から言うと受信側で通番を除去してあげないと開けません。これはごく当然のことです。例えば拡張子.bmpの画像ファイルをバイナリエディタで開くと先頭に、文字「BM」を表すコードが入っています。例えばWindows標準のペイントなどはファイル先頭の「BM」を見て、それ以降のデータをビットマップ形式の画像と認識しています。もしこのファイルの先頭(本来はBMが入っている部分)に通番があったら、ペイントはファイルの形式を判断できず、表示できないことになります。
同じ理由から、送信元のファイルを受信側で復元するには、アプリケーションの都合で付与した通番などを除去して、本来送信したかったバイナリデータを復元してあげる必要があります。
データ部分をズラして先頭に通番を入れることができたのですから、逆のこともできると思います。がんばってください。
    • good
    • 0
この回答へのお礼

こんばんわ。
とても分かりやすい回答を多々ありがとうございます。
大変参考になりました。

今後もこのプログラムの拡張を続けて行くつもりです。
ありがとうございました。

お礼日時:2006/10/17 23:04

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