マルチスレッドプログラミングについて


rockfish  2006-11-15 23:40:48  No: 63615

こんにちは。
初めて投稿させていただきます。

私は、VC++.NETを用いてコンソール上でUDPソケットプログラミングを行なっています。
UDPには、再送を行なう機能がないためUDPを用いて再送を行なうアプリケーションを構築しています。

ネットワーク構成は、送信側と受信側です。

以下がプログラムです。
このプログラムは、パケット送信スレッドおよびパケット受信スレッドで構成されています。

(送信スレッド)
fread関数により1024Byteずつバイナリデータを抽出し、sprintf関数にて通番をふかし、PktBuffへ格納(①部)。そして、sendto関数にてパケットを送信しています。

(受信スレッド)
recvfrom関数により、受信側で取得できなかった番号を受信しています。

[質問事項]
送信スレッドで、送信したパケットが100個になると一時的に送信スレッドを停止させます。
そして、受信スレッド内に通番があれば再送スレッドを生成し、なければ、送信スレッドを再開させる。

というプログラムを考えているのですが、これはCreateEvent関数を用いる事で可能でしょうか?

また、送信スレッド内で構造体を用いて100パケット格納(②部)しているのですが、受信スレッドから送信スレッドへアクセス可能でしょうか?

よろしくお願いします。

#ifndef Boolean
#define Boolean int
#endif

#ifndef TRUE
#define TRUE 0
#endif

#define SEND_DATA_SIZE 1024

//構造体
struct SPkt{
  UINT SeqNum;
  char SPkt_Buf[1500];
}SendPkt;

//グローバル関数
HANDLE hEvent[3];

//受信側からの通番受信部
Boolean feedback_packet(){

  //recvfromにより通番を受信
  recvfrom();

  //★受信側で取得できなかった通番を受信。

  return(TRUE);

}

//受信スレッド
unsigned __stdcall Feedback_Pkt(void *lpx){
  
  if(feedback_packet() == TRUE);

  SetEvent(hEvent[1]);

  return 0;

}

//パケット送出部
int udpdatasend(char *PktBuff){

   //sendtoにより受信
   sendto(PktBuff);

   return 0;
}

//パケット処理
int udpsending(){

  int n,s;
  int SeqN = 0;
  char PktBuf[1024],PktBuff[1024];
  struct SPkt Pkt_Array[100];

  //fread関数にて、1024Byteずつバイナリデータを取り出す
  while((n = fread(PktBuf, sizeof(char), SEND_DATA_SIZE, fp)) != 0) {

     //通番カウント
     SeqN++;

     //①sprintfおよびmemmove関数にて、PktBuffに通番+バイナリデータを格納
     s = sprintf(PktBuff,"%d\0",SeqN);
     memmove(&PktBuff[s+1],&PktBuf[0],n);

     //②送信データを構造体を用意し、通番とバイナリデータを対にして格納(100個)
     Pkt_Array[c].SeqNum = SeqN;
     memmove(&Pkt_Array[c].SPkt_Buf[0],PktBuf[0],n);
    
     udpdatasend(PktBuff);

     if(SeqN%100==0){
  //★Send_Pktスレッド一時停止
     }
   }
   return 0;
}

//送信スレッド
unsigned __stdcall Send_Pkt(void *lpx){

   udpsending();

   WaitForSingleObject(hEvent[1],INFINITE);
   SetEvent(hEvent[2]);

   return 0;
}

int main(){
   HANDLE hTh[2];
   unsigned int thID[2];

   hEvent[0] = CreateEvent(NULL, TRUE, FALSE, "CH0");
   hEvent[1] = CreateEvent(NULL, TRUE, FALSE, "CH1");
   hEvent[2] = CreateEvent(NULL, TRUE, FALSE, "MAINEVENT");

   //Send_Pktスレッド生成
   hTh[0] = (HANDLE)_beginthreadex(NULL, 0, Send_Pkt, NULL, 0, &thID[0]);
 
   
   //Feedback_Pktスレッド生成
   hTh[1] = (HANDLE)_beginthreadex(NULL, 0, Feedback_Pkt, NULL, 0, &thID[1]);

   WaitForSingleObject(hEvent[2], INFINITE);

   //スレッド終了
   for(i=0;i<2;i++)
  CloseHandle(hTh[i]);
}


774  2006-11-16 05:37:38  No: 63616

なんでわざわざUDPを使うんだろう。ありえない。


車輪  2006-11-16 10:36:28  No: 63617

初心者にありがちな「車輪の再発明」ですな。

UDPに自家製のエラー処理を追加してTCPにしようとする人って、本当に絶えんね。


nowhere  2006-11-16 21:21:25  No: 63618

勉強にはいいし、目的によってせざるをえない場合があるので、車輪の再発明の是非については置いておいて気になったところを。

(1) の memmove で連番の後ろにデータを付記しているが、データ長が1024付近だった場合、後ろの方がバッファーオーバーフローする。

(2) の memmove で n バイトパケットにコピーしているが、連番のデータ長を考慮していない。 n+s にするべき

質問に関しては、プログラムの意図が不明(サーバ/クライアントじゃないの?とか、自分で送ったものを自分で受け取るの?など)なので、正確には答えられませんが。

> これはCreateEvent関数を用いる事で可能でしょうか?
受信プロセスと送信プロセスが同一なら可能ですが、それならネットワークを介する意味が全くないでしょう。
受信プロセスと送信プロセスが別でかつ、自分の送信したデータが相手側の受信状況を確認したい、というのでしたら基本的にはムリです。
#同一マシンのプロセス同士なら名前付きイベントを使えばできないこともないですが、やっぱりネットワークを介する意味がない

> また、送信スレッド内で構造体を用いて100パケット格納((2)部)しているのですが、受信スレッドから送信スレッドへアクセス可能でしょうか?
同一プロセス内でしたら、別スレッドのデータにアクセスすることは可能です。
もちろん、同期処理に十分注意しないといけませんが。

なにをしたいのかもう少し詳しく書いてないと、答えもあやふやになってしまいます。


rockfish  2006-11-18 04:43:06  No: 63619

返信ありがとうございます。
UDPではなく、TCPを用いればよいとのご意見ですが、UDPを用いてアプリケーションレベルで再送を行う手順を勉強している次第です。

>(1) の memmove で連番の後ろにデータを付記しているが、データ長が1024付近だった場合、後ろの方がバッファーオーバーフローする。
PktBuff[1024]をPktBuff[1500]へ変更すればオーバーフロー問題は発生しないでしょうか?

>(2) の memmove で n バイトパケットにコピーしているが、連番のデータ>長を考慮していない。 n+s にするべき
もしわけありません、この方法については、異なった方法を模索中です。

>受信プロセスと送信プロセスが同一なら可能ですが、それならネットワークを介する意味が全くないでしょう。
同一とはどのような意味でしょうか?送信側において、送信・受信スレッドを生成しております。

>なにをしたいのかもう少し詳しく書いてないと、答えもあやふやになってしまいます。

[実行したいこと]
・送信側から受信側へfread関数によって抽出したデータ+通番を送信。
・受信側は、通番+バイナリデータを受信し、取得できなかった通番を送信側へ送信。
・取得できなかった通番と対となるバイナリデータを送信側から再送信。

このようなことを実行したいと思っています。

よろしくお願いします。


isshi  2006-11-18 06:02:37  No: 63620

回答ではありませんが。

>・受信側は、通番+バイナリデータを受信し、取得できなかった通番を送信側へ送信。
取得できなかったことを送信側へ送信しても、送信側がそれを受信できなかったらどうなる? かなり面倒なことになりそうですが。


デットロック  2006-11-18 09:54:24  No: 63621

ある程度時間が経っても「取得できなかった事を知らせるデータ」が来なければ受信に失敗したと想定して、相手に再送信を依頼する

でも相手がその受信に失敗した

さらにある程度時間が経っても「取得できなかった事を知らせるデータが取得できなかった事を知らせるデータ」が来なければ受信に失敗したと想定して、相手に再送信を依頼する

でも相手がその受信に失敗した

「取得できなかった事を知らせるデータが取得できなかった事を知らせるデータが取得できなかった事を知らせるデータ」を…


774  2006-11-18 18:59:20  No: 63622

まあそういうことを考える必要があるのでUDPで再送ロジックを考えるのは
労多くして功少なし、って奴。
自分より頭が良くて、そういうことを専門にしてる人が作ったロジックは
ありがたく利用させてもらうのが絶対に良い。

UDPの使い方の勉強をしたいのならisochronous通信でもしてみるべし
再送する通信がしたいのならTCPの勉強をするべし
マルチスレッドの勉強がしたいのならもっと簡単な題材にすべし
TCPが使えない(UDPしか使えない)LANがあるなら管理人に直談判すべし


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加