• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:配列内に通番(文字列)を挿入したいのですが・・・(Winsock利用))

配列内に通番(文字列)を挿入したいのですが・・・(Winsock利用)

このQ&Aのポイント
  • Winsockを利用して配列内に通番を挿入する方法について教えてください。
  • UDPを用いて、A端末から複数パケットを送信し、B端末で受信するプログラムを作成しています。A端末において各パケットに通番のようなものを挿入し、B端末で受信したパケットの通番を確認したいです。
  • 実装したいことは、A端末において各パケットに通番のようなものを挿入し、B端末で受信したパケットの通番を確認することです。具体的なプログラムの作成方法について教えてください。

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

  • ベストアンサー
  • meruty
  • ベストアンサー率81% (9/11)
回答No.1

こんばんわ。 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); } 試してませんが、考え方のひとつとして参考になればと思います。

bird0214
質問者

補足

こんばんわ。回答ありがとうございます。 参考にさせていただきます。 >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])までがバイナリデータとなると思っています。 よろしくお願いします。

すると、全ての回答が全文表示されます。

その他の回答 (4)

  • meruty
  • ベストアンサー率81% (9/11)
回答No.5

こんばんわ。 上書きについてご理解いただけて何よりです。 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が入っている部分)に通番があったら、ペイントはファイルの形式を判断できず、表示できないことになります。 同じ理由から、送信元のファイルを受信側で復元するには、アプリケーションの都合で付与した通番などを除去して、本来送信したかったバイナリデータを復元してあげる必要があります。 データ部分をズラして先頭に通番を入れることができたのですから、逆のこともできると思います。がんばってください。

bird0214
質問者

お礼

こんばんわ。 とても分かりやすい回答を多々ありがとうございます。 大変参考になりました。 今後もこのプログラムの拡張を続けて行くつもりです。 ありがとうございました。

すると、全ての回答が全文表示されます。
  • meruty
  • ベストアンサー率81% (9/11)
回答No.4

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

すると、全ての回答が全文表示されます。
  • meruty
  • ベストアンサー率81% (9/11)
回答No.3

補足ありがとうございます。 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です。 通番で送信データの一部が上書きされてしまいますが、パケットごとに通番が埋め込まれることにはなっています。

すると、全ての回答が全文表示されます。
  • meruty
  • ベストアンサー率81% (9/11)
回答No.2

補足ありがとうございます。 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
bird0214
質問者

お礼

申し訳ありません。 追加質問しました、受信側において取得できたパケットの通番をファイル出力する機能についての質問でしたが、 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バイトで送信しています。通番を付加して送信するため、受信側においてファイルを開くことができません。これは当たり前?のことなのでしょうか。

bird0214
質問者

補足

こんにちは。 返答ありがとうございます。 >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]); } なにか解決策はありますでしょうか? よろしくお願いいたします。

すると、全ての回答が全文表示されます。

関連するQ&A