''[[FrontPage]]''
* C++/ソケットサンプル2(Windowsサーバ・クライアント) [#e80cca2a]
Windows上でサーバ及びクライアントとして動作するサンプルを解説する。~
引数1に(1: クライアント、2: サーバ、3: 両方)を指定。~
引数2に接続先ホスト名を指定。~

[[C++/ソケットサンプル1(Linuxサーバ)]]~
[[Java/ソケットサンプル]]

** 制約 [#k448f33e]
サンプルとして、ホスト名"clove.la"でアクセスできること。~
サンプルとして、ポート"57891"でアクセスできること。~
コンパイルのコマンドラインは"cl.exe seqSv.cpp"
~
~
ファイル名: seqSv.cpp
 #include        <stdio.h>                                       //  標準入出力                                    //
 #include        <time.h>                                        //  時間計測のため                                //
 //#include        <tchar.h>                                       //  for TCHAR etc.                                //
                                                                 //                                                //
 //#define         WIN32                                           //  WIN32API用プリコンパイル指示                  //
 #define         ARG_NUM         2                               //  引数の数                                      //
 #define         MAX_SESSIONS    2                               //  最大セッション数                              //
 #define         RET_OK          0                               //  正常終了                                      //
 #define         RET_NG          (-1)                            //  異常終了                                      //
 #define         IND_TRUE        10                              //  真                                            //
 #define         IND_FALSE       0                               //  偽                                            //
 #define         SV_PORT         57891                           //  使用ポート                                    //
 #define         ZERO            0                               //  そのまま                                      //
 #define         SOCK_TIMER      5                               //  ソケット接続待ち等タイマ                      //
 #define         DEF_BUFF_LEN    1200                            //  通常バッファ長                                //
                                                                 //                                                //
 #ifdef WIN32                                                    //  Windows環境の場合                             //
 //#include        <windows.h>                                     //  for win32API                                  //
 #include        <winsock2.h>                                    //  winsockAPIを使用                              //
 #include        <process.h>                                     //  for _beginthreadex()                          //
 #pragma         once                                            //  インクルードガード                            //
 #pragma         comment(lib,"ws2_32.lib")                       //  for winsock                                   //
 #else                                                           //  Unix環境の場合                                //
 #include        <unistd.h>                                      //  Unix標準ヘッダ                                //
 #include        <sys/socket.h>                                  //  sys/socketライブラリを使用                    //
 #include        <arpa/inet.h>                                   //  arpa/inetライブラリを使用                     //
 #include        <netdb.h>                                       //  netdbライブラリを使用                         //
 #endif                                                          //                                                //
                                                                 //                                                //
 unsigned long   vc_svAddr;                                      //  サーバアドレス                                //
                                                                 //                                                //
 /* Class Multi Thread *****************************************//*  マルチスレッド基底クラス                      */
 class           cl_mt                                           //  マルチスレッド基底クラス                      //
 {                                                               //                                                //
 private:                                                        //  非公開属性                                    //
                                                                 //                                                //
 protected:                                                      //  保護属性                                      //
     HANDLE vc_handle;                                           //  スレッドハンドル                              //
     HANDLE vc_events[2];                                        //  スレッド操作イベントハンドル                  //
     unsigned int vc_threadId;                                   //  スレッドID                                    //
     int vc_kill_threads;                                        //  スレッド終了指示                              //
                                                                 //                                                //
 public:                                                         //  公開属性                                      //
     cl_mt();                                                    //  コンストラクタ                                //
     ~cl_mt();                                                   //  デストラクタ                                  //
                                                                 //                                                //
     char        init( void );                                   //  初期化処理                                    //
     virtual char create_thread( void ){ return( RET_OK ); };    //  スレッド生成処理                              //
     char        destroyThreads( void );                         //  スレッド破棄処理                              //
 };                                                              //                                                //
 //*Class Multi Thread *****************************************//*  マルチスレッド基底クラス                      */
 /* Class Server ***********************************************//*  チャットサーバークラス                        */
 class           cl_server : public cl_mt                        //  チャットサーバークラス                        //
 {                                                               //                                                //
 private:                                                        //  非公開属性                                    //
     SOCKET vc_sv_sessions[MAX_SESSIONS + 1];                    //  ソケット保持用                                //
     int vc_sv_sessionId;                                        //  セッションID指示用                            //
                                                                 //                                                //
 public:                                                         //  公開属性                                      //
     cl_server();                                                //  コンストラクタ                                //
     ~cl_server();                                               //  デストラクタ                                  //
                                                                 //                                                //
     virtual char create_thread( void );                         //  スレッド生成処理                              //
     unsigned int static __stdcall th_receiver( void* );         //  メッセージ受信スレッド                        //
                                                                 //                                                //
     char addFd( SOCKET vd_sock, fd_set* vd_fds )                //  fdsにソケットを追加する                       //
     {                                                           //                                                //
 #pragma warning( disable:4127 )                                 //  一時的に警告を無効にする                      //
         FD_SET( vd_sock, vd_fds );                              //  fdsにソケット登録                             //
 #pragma warning( default:4127 )                                 //  警告を有効にする                              //
         return( RET_OK );                                       //  正常終了                                      //
     }                                                           //                                                //
                                                                 //                                                //
     char delFd( SOCKET vd_sock, fd_set* vd_fds )                //  fdsからソケットを解放する                     //
     {                                                           //                                                //
 #pragma warning( disable:4127 )                                 //  一時的に警告を無効にする                      //
         FD_CLR( vd_sock, vd_fds );                              //  fdsからソケット解放                           //
 #pragma warning( default:4127 )                                 //  警告を有効にする                              //
         return( RET_OK );                                       //  正常終了                                      //
     }                                                           //                                                //
 };                                                              //                                                //
                                                                 //                                                //
 cl_server   obj_server;                                         //  クライアントクラスの実体化                    //
 //extern  cl_server   obj_server;                                 //  実体化した自クラスの参照                      //
 //*Class Server ***********************************************//*  チャットサーバークラス                        */
 /* Class Client ***********************************************//*  チャットクライアントクラス                    */
 class           cl_client : public cl_mt                        //  チャットクライアントクラス                    //
 {                                                               //                                                //
 private:                                                        //  非公開属性                                    //
                                                                 //                                                //
 public:                                                         //  公開属性                                      //
     cl_client();                                                //  コンストラクタ                                //
     ~cl_client();                                               //  デストラクタ                                  //
                                                                 //                                                //
     virtual char create_thread( void );                         //  スレッド生成処理                              //
     unsigned int static __stdcall th_receiver( void* );         //  メッセージ受信スレッド                        //
 };                                                              //                                                //
                                                                 //                                                //
 cl_client   obj_client;                                         //  クライアントクラスの実体化                    //
 //extern  cl_client   obj_client;                                 //  実体化した自クラスの参照                      //
 //*Class Client ***********************************************//*  チャットクライアントクラス                    */
 /* Main *******************************************************//*  起動処理                                      */
 char main( int argc, char **argv )                              //                                                //
 {                                                               //                                                //
     clock_t start, end;                                         //  時間計測用                                    //
     start = clock();                                            //  時間計測スタート                              //
                                                                 //                                                //
     char rtnCod = RET_OK;                                       //  リターンコード                                //
     int mode;                                                   //  動作モード                                    //
     HOSTENT *host;                                              //  ホスト関連情報                                //
     int index = RET_OK;                                         //  内部処理判定用                                //
     WSADATA wsadata;                                            //  Windowsソケット関連情報                       //
                                                                 //                                                //
     for( ; ; )                                                  //  無限ループ                                    //
     {                                                           //                                                //
         if( ARG_NUM >= argc )                                   //  引数の数が足りないか                          //
         {                                                       //  引数の数が足りない場合                        //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
             printf( "argments required.\n\n" );                 //  画面表示                                      //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         mode = atoi(argv[1]);                                   //  動作モードを取得                              //
         if( 1 > mode )                                          //  動作モードが無効値か                          //
         {                                                       //  動作モードが無効値なら                        //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
             printf( "mode: \n1 - client only.\n2 - server only.\n3 - both.\n" ); //  画面表示                     //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         index = WSAStartup( MAKEWORD(2, 2), &wsadata );         //  Windowsソケット初期化                         //
         if( RET_OK != index )                                   //  Windowsソケット初期化に失敗したか             //
         {                                                       //  Windowsソケット初期化に失敗した場合           //
             printf( "WSAStartup failed.\n" );                   //  画面表示                                      //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         vc_svAddr = inet_addr( argv[2] );                       //  ホストアドレスを取得                          //
         if( RET_NG == vc_svAddr )                               //  ホストアドレス取得に失敗したか                //
         {                                                       //  ホストアドレス取得に失敗した場合              //
             host = gethostbyname( argv[2] );                    //  ドメイン名からアドレス変換を試行              //
             if( NULL != host )                                  //  アドレス変換に成功したか                      //
             {                                                   //  アドレス変換に成功した場合                    //
                 vc_svAddr = *((unsigned long *)(host->h_addr)); //  ホストアドレス保持                            //
             }                                                   //                                                //
             else                                                //  アドレス変換に失敗した場合                    //
             {                                                   //                                                //
                 printf( "invalid addr or hostname.\n" );        //  画面表示                                      //
                 printf( "error: %d\n", WSAGetLastError() );     //  画面表示                                      //
                 rtnCod = RET_NG;                                //  リターンにNGを設定                            //
                 break;                                          //  処理終了                                      //
             }                                                   //                                                //
         }                                                       //                                                //
                                                                 //                                                //
         if( 2 == (2 & mode) )                                   //  サーバ動作モードが設定されているか            //
         {                                                       //  サーバ動作モードが設定されている場合          //
             obj_server.init();                                  //  サーバ初期化依頼                              //
         }                                                       //                                                //
                                                                 //                                                //
         if( 1 == (1 & mode) )                                   //  クライアント動作モードが設定されているか      //
         {                                                       //  クライアント動作モードが設定されている場合    //
             obj_client.init();                                  //  クライアント初期化依頼                        //
         }                                                       //                                                //
                                                                 //                                                //
         end = clock();                                          //  時間計測ストップ                              //
         printf( "it takes %d msec.\n\n", end - start );         //  画面表示                                      //
         getchar();                                              //  一時停止のため                                //
                                                                 //                                                //
         if( 1 == (1 & mode) )                                   //  クライアント動作モードが設定されているか      //
         {                                                       //  クライアント動作モードが設定されている場合    //
             obj_client.destroyThreads();                        //  クライアントスレッド終了依頼                  //
         }                                                       //                                                //
                                                                 //                                                //
         if( 2 == (2 & mode) )                                   //  サーバ動作モードが設定されているか            //
         {                                                       //  サーバ動作モードが設定されている場合          //
             obj_server.destroyThreads();                        //  サーバスレッド終了依頼                        //
             Sleep( 5000 );                                      //  サーバスレッド解放のため                      //
         }                                                       //                                                //
                                                                 //                                                //
         getchar();                                              //  一時停止のため                                //
                                                                 //                                                //
         if( SOCKET_ERROR == WSACleanup() )                      //  Windowsソケット解放を試行                     //
         {                                                       //  Windowsソケット解放に失敗した場合             //
             printf( "failed to WSACleanup().\n\n" );            //  画面表示                                      //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
         }                                                       //                                                //
                                                                 //                                                //
         break;                                                  //  処理終了                                      //
     }                                                           //                                                //
                                                                 //                                                //
     return( RET_OK );                                           //  処理終了                                      //
 }                                                               //                                                //
 //*Main *******************************************************//*  起動処理                                      */
 /* Server Receiver Thread *************************************//*  クライアント受信待ちスレッド作成処理          */
 unsigned int __stdcall cl_server::th_receiver( void* )          //  メッセージ受信スレッド                        //
 {                                                               //                                                //
     char rtnCod = RET_OK;                                       //  終了コード                                    //
     int errInd;                                                 //  エラー番号保持用                              //
     int clAddrLen;                                              //  クライアント側アドレス文字列長                //
     int index = RET_OK;                                         //  内部処理判定用                                //
                                                                 //                                                //
     struct sockaddr_in svAddr;                                  //  ソケットアドレス関連情報(サーバ側)            //
     struct sockaddr_in clAddr;                                  //  ソケットアドレス関連情報(クライアント側)      //
     IN_ADDR clInAddr;                                           //  クライアント側アドレス確認用                  //
                                                                 //                                                //
     SOCKET sock = NULL;                                         //  基底ソケット                                  //
     SOCKET clSock = NULL;                                       //  個別ソケット操作用                            //
     char bufStr[DEF_BUFF_LEN] = "";                             //  メッセージ文字列操作用                        //
     int recvBytes;                                              //  受信バイト数確認用                            //
     int sessionNum = ZERO;                                      //  セッション数保持用                            //
     int sessionIndicator;                                       //  セッションID取得用                            //
     int cnt;                                                    //  ループカウンタ                                //
     int firstInd = IND_TRUE;                                    //  初回処理判定用                                //
     struct timeval tmVal = { SOCK_TIMER, ZERO };                //  select用タイマ値                              //
     fd_set readFd = { ZERO, };                                  //  ソケット監視用fds                             //
     fd_set initFd = { ZERO, };                                  //  ソケット追加・解放用fds                       //
                                                                 //                                                //
     FD_ZERO( &initFd );                                         //  ソケット追加・解放用fdsを初期化               //
                                                                 //                                                //
     for( ; ; )                                                  //  無限ループ                                    //
     {                                                           //                                                //
 //        printf( "This is server's thread.\n\n" );               //  画面表示                                      //
         WaitForSingleObject( obj_server.vc_events[1], INFINITE ); //  イベント1(報知)を待つ                       //
 //        ResetEvent( obj_server.vc_events[1] );                    //  イベント1(報知)を非シグナル状態にする       //
         printf( "This is server's thread.\n\n" );               //  画面表示                                      //
                                                                 //                                                //
         if( IND_TRUE == obj_server.vc_kill_threads )            //  スレッド終了指示が指示ありか                  //
         {                                                       //  スレッド終了指示が指示ありなら                //
             for( cnt = ZERO; MAX_SESSIONS > cnt; cnt++ )        //  すべてのセッションIDについて                  //
             {                                                   //                                                //
                 if( NULL != obj_server.vc_sv_sessions[cnt] )    //  ソケットが接続済か                            //
                 {                                               //  ソケットが接続済なら                          //
                     send( clSock, "closed by network.\n\n", 21, 0 ); //  ネットワーク切断である旨を通知           //
                     shutdown( clSock, 2 );                      //  送受信中止                                    //
                     closesocket( clSock );                      //  ソケット解放                                  //
                 }                                               //                                                //
             }                                                   //                                                //
                                                                 //                                                //
             printf( "Server's thread killed.\n\n" );            //  画面表示                                      //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         if( IND_TRUE == firstInd )                              //  初回処理判定指示があるか                      //
         {                                                       //  初回処理判定指示がある場合                    //
             firstInd = IND_FALSE;                               //  初回処理判定指示になしを設定                  //
             sock = socket( AF_INET, SOCK_STREAM, 0 );           //  基底ソケットを生成                            //
             if( INVALID_SOCKET == sock )                        //  基底ソケット生成に失敗したか                  //
             {                                                   //  基底ソケット生成に失敗した場合                //
                 printf("failed to generate socket.\n");         //  画面表示                                      //
                 rtnCod = RET_NG;                                //  リターンにNGを設定                            //
                 break;                                          //  処理終了                                      //
             }                                                   //                                                //
                                                                 //                                                //
             memset( &svAddr, 0, sizeof(IN_ADDR) );              //  念のため                                      //
             svAddr.sin_family = AF_INET;                        //  アドレスファミリ                              //
             svAddr.sin_port = htons( SV_PORT );                 //  ポート                                        //
             svAddr.sin_addr.S_un.S_addr = INADDR_ANY;           //  アドレス                                      //
                                                                 //                                                //
             index = bind( sock, (struct sockaddr *)&svAddr, sizeof(svAddr) ); //  ソケットとポートの関連付け      //
             if( SOCKET_ERROR == index )                         //  bindに失敗したか                              //
             {                                                   //  bindに失敗した場合                            //
                 printf("failed to bind socket.\n");             //  画面表示                                      //
                 closesocket( sock );                            //  ソケット解放                                  //
                 rtnCod = RET_NG;                                //  リターンにNGを設定                            //
                 break;                                          //  処理終了                                      //
             }                                                   //                                                //
                                                                 //                                                //
             index = listen( sock, MAX_SESSIONS + 1 );           //  ソケット接続準備                              //
             if( SOCKET_ERROR != index )                         //  listenに失敗したか                            //
             {                                                   //  listenに失敗した場合                          //
                 printf("waiting for clients.\n\n");             //  画面表示                                      //
                 clAddrLen = sizeof(clAddr);                     //  アドレス文字列長取得                          //
             }                                                   //                                                //
             else                                                //  listenに成功した場合                          //
             {                                                   //                                                //
                 printf("failed to listen socket.\n");           //  画面表示                                      //
                 closesocket( sock );                            //  ソケット解放                                  //
                 rtnCod = RET_NG;                                //  リターンにNGを設定                            //
                 break;                                          //  処理終了                                      //
             }                                                   //                                                //
                                                                 //                                                //
             obj_server.addFd( sock, &initFd );                  //  基底ソケットをfdsに登録                       //
         }                                                       //                                                //
                                                                 //                                                //
         for( ; ; )                                              //  select無限ループ                              //
         {                                                       //                                                //
             memcpy( &readFd, &initFd, sizeof(fd_set) );         //  ソケット監視fdsを登録時のfdsに戻す            //
             if( IND_TRUE == obj_server.vc_kill_threads )        //  スレッド終了指示が指示ありか                  //
             {                                                   //  スレッド終了指示が指示ありなら                //
                 break;                                          //  selectループを抜けた先で処理終了              //
             }                                                   //                                                //
                                                                 //                                                //
             index = select( 0, &readFd, NULL, NULL, &tmVal );   //  ソケットからの情報を監視                      //
             if( FD_ISSET( sock, &readFd) )                      //  基底ソケットに変化があったか                  //
             {                                                   //  基底ソケットに変化があった場合                //
                 clSock = accept( sock, (LPSOCKADDR)&clAddr, &clAddrLen ); //  個別ソケット接続を試行              //
                 if( INVALID_SOCKET != clSock )                  //  acceptに成功したか                            //
                 {                                               //  acceptに成功した場合                          //
                     memcpy( &clInAddr, &clAddr.sin_addr.s_addr, 4 ); //  アドレス取得                             //
                     printf( "a client accepted: %s\n\n", inet_ntoa( clInAddr ) ); //  画面表示                    //
                                                                 //                                                //
                     if( MAX_SESSIONS == sessionNum )            //  セッション数が最大であるか                    //
                     {                                           //  セッション数が最大である場合                  //
                         printf( "session full.\n\n" );          //  画面表示                                      //
                         _snprintf_s( bufStr, sizeof(bufStr), 16, "%s", "server busy.\n\n" ); //  メッセージ編集   //
                         send( clSock, bufStr, strlen(bufStr), 0 ); //  セッション数が最大である旨を通知           //
                         shutdown( clSock, 2 );                  //  送受信中止                                    //
                         closesocket( clSock );                  //  ソケット解放                                  //
                         continue;                               //  selectループに戻る                            //
                     }                                           //                                                //
                                                                 //                                                //
                     for( sessionIndicator = ZERO;               //  すべてのセッションIDについて                  //
                          MAX_SESSIONS > sessionIndicator; sessionIndicator++ ) //                                 //
                     {                                           //                                                //
                         if( NULL == obj_server.vc_sv_sessions[sessionIndicator] ) //  ソケットが未接続か          //
                         {                                                         //  ソケットが未接続なら        //
                             obj_server.vc_sv_sessions[sessionIndicator] = clSock; //  セッションを保持            //
                             printf( "session ID: %d\n\n", sessionIndicator );     //  画面表示                    //
                             obj_server.addFd( clSock, &initFd ); //  ソケットをfdsに登録                          //
                             sessionNum++;                       //  セッション数をインクリメント                  //
                             printf( "sessions: %d\n\n", sessionNum ); //  画面表示                                //
                             break;                              //  セッションを保持したらループを抜ける          //
                         }                                       //                                                //
                     }                                           //                                                //
                 }                                               //                                                //
                 else                                            //  acceptに失敗した場合                          //
                 {                                               //                                                //
                     printf( "failed to accept.\n" );            //  画面表示                                      //
                     printf( "error: %d\n", WSAGetLastError() ); //  画面表示                                      //
                     closesocket( sock );                        //  ソケット解放                                  //
                     rtnCod = RET_NG;                            //  リターンにNGを設定                            //
                     break;                                      //  処理終了                                      //
                 }                                               //                                                //
             }                                                   //                                                //
                                                                 //                                                //
             for( cnt = ZERO; MAX_SESSIONS > cnt; cnt++ )        //  すべての個別セッションについて                //
             {                                                   //                                                //
                 if( FD_ISSET(obj_server.vc_sv_sessions[cnt], &readFd) ) //  情報が通知されているか確認する        //
                 {                                               //                                                //
                     clSock = obj_server.vc_sv_sessions[cnt];    //  対象個別ソケット操作用                        //
                     recvBytes = recv( clSock, bufStr, sizeof(bufStr), 0 ); //  メッセージ受信を試行               //
                     printf( "recvBytes = %d.\n\n", recvBytes ); //  画面表示                                      //
                     if( SOCKET_ERROR == recvBytes )             //  受信エラーか                                  //
                     {                                           //                                                //
                         errInd = WSAGetLastError();             //  エラー番号を保持                              //
                         if( WSAECONNRESET == errInd )           //  エラー番号がセッションクローズか              //
                         {                                       //  エラー番号がセッションクローズなら            //
                             printf( "session closed.\n\n" );    //  画面表示                                      //
                         }                                       //                                                //
                         else                                    //  エラー番号がセッションクローズ以外なら        //
                         {                                       //                                                //
                             printf( "failed to receive.\n" );   //  画面表示                                      //
                             printf( "error: %d\n", errInd );    //  画面表示                                      //
                         }                                       //                                                //
                         obj_server.delFd( clSock, &initFd );    //  ソケットをfdsから解放                         //
                         obj_server.vc_sv_sessions[cnt] = NULL;  //  保持ソケットを解放                            //
                         closesocket( clSock );                  //  ソケット解放                                  //
                         sessionNum--;                           //  セッション数をデクリメント                    //
                         continue;                               //  次の個別セッションに進む                      //
                     }                                           //                                                //
                     else if( ZERO == recvBytes )                //  受信バイト数がZEROか                          //
                     {                                           //  受信バイト数がZEROなら                        //
                         printf( "session closed.\n\n" );        //  画面表示                                      //
                         obj_server.delFd( clSock, &initFd );    //  ソケットをfdsから解放                         //
                         obj_server.vc_sv_sessions[cnt] = NULL;  //  保持ソケットを解放                            //
                         closesocket( clSock );                  //  ソケット解放                                  //
                         sessionNum--;                           //  セッション数をデクリメント                    //
                         continue;                               //  以降のループ処理をスキップ                    //
                     }                                           //                                                //
                     bufStr[recvBytes] = '\0';                   //  文字列終端の付与                              //
                     printf( "server rec: %s\n", bufStr );       //  画面表示                                      //
                                                                 //                                                //
                     index = send( clSock, bufStr, strlen(bufStr), 0 ); //  メッセージ送信                         //
                     if( SOCKET_ERROR == index )                 //  メッセージ送信に失敗したか                    //
                     {                                           //  メッセージ送信に失敗した場合                  //
                         printf( "failed to send.\n" );          //  画面表示                                      //
                         printf( "error: %d\n", WSAGetLastError() ); //  画面表示                                  //
                         obj_server.delFd( clSock, &initFd );    //  ソケットをfdsから解放                         //
                         obj_server.vc_sv_sessions[cnt] = NULL;  //  保持ソケットを解放                            //
                         shutdown( clSock, 2 );                  //  送受信中止                                    //
                         closesocket( clSock );                  //  ソケット解放                                  //
                         sessionNum--;                           //  セッション数をデクリメント                    //
                         rtnCod = RET_NG;                        //  リターンにNGを設定                            //
                         continue;                               //  以降のループ処理をスキップ                    //
                     }                                           //                                                //
                 }                                               //                                                //
             }                                                   //                                                //
             printf( "go next selection.\n\n" );                 //  画面表示                                      //
         }                                                       //                                                //
     }                                                           //                                                //
                                                                 //                                                //
     shutdown( sock, 2 );                                        //  送受信中止                                    //
     shutdown( clSock, 2 );                                      //  送受信中止                                    //
     closesocket( sock );                                        //  ソケット解放                                  //
     closesocket( clSock );                                      //  ソケット解放                                  //
                                                                 //                                                //
     _endthreadex( rtnCod );                                     //  スレッド処理終了                              //
     return( rtnCod );                                           //  リターンを返して終了                          //
 }                                                               //                                                //
 //*Server Thread **********************************************//*  サーバスレッド作成処理                        */
 /* Client Receiver Thread *************************************//*  クライアント受信待ちスレッド作成処理          */
 unsigned int __stdcall cl_client::th_receiver( void* )          //  メッセージ受信スレッド                        //
 {                                                               //                                                //
     char rtnCod = RET_OK;                                       //  終了コード                                    //
     int index = RET_OK;                                         //  内部処理判定用                                //
     SOCKET sock = NULL;                                         //  自ソケット操作用                              //
     unsigned long svAddr = vc_svAddr;                           //  サーバIPアドレスのローカルコピー              //
     SOCKADDR_IN svAddrInfo;                                     //  サーバ情報                                    //
     char msg[DEF_BUFF_LEN] = "";                                //  メッセージ文字列操作用                        //
     int recvBytes;                                              //  受信バイト数取得用                            //
                                                                 //                                                //
     for( ; ; )                                                  //  無限ループ                                    //
     {                                                           //                                                //
         WaitForSingleObject( obj_client.vc_events[1], INFINITE ); //  イベント1(報知)を待つ                       //
         ResetEvent( obj_client.vc_events[1] );                    //  イベント1(報知)を非シグナル状態にする       //
         printf( "This is client's thread.\n\n" );               //  画面表示                                      //
                                                                 //                                                //
         if( IND_TRUE == obj_client.vc_kill_threads )            //  スレッド終了指示が指示ありか                  //
         {                                                       //  スレッド終了指示が指示ありなら                //
             printf( "Client's thread killed.\n\n" );            //  画面表示                                      //
             closesocket( sock );                                //  ソケットクローズ                              //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         sock = socket( AF_INET, SOCK_STREAM, 0 );               //  自ソケット生成                                //
         if( INVALID_SOCKET == sock )                            //  自ソケット生成に失敗したか                    //
         {                                                       //  自ソケット生成に失敗した場合                  //
             printf("failed to generate socket.\n");             //  画面表示                                      //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         svAddrInfo.sin_family = AF_INET;                        //  アドレスファミリ                              //
         svAddrInfo.sin_addr.s_addr = svAddr;                    //  サーバIPアドレス                              //
         svAddrInfo.sin_port = htons( (unsigned short)SV_PORT ); //  ポート番号                                    //
                                                                 //                                                //
         index = connect( sock, (LPSOCKADDR)&svAddrInfo, sizeof(svAddrInfo) ); //  接続要求                        //
         if( SOCKET_ERROR == index )                             //  connectに失敗したか                           //
         {                                                       //  connectに失敗した場合                         //
             printf( "failed to connect.\n" );                   //  画面表示                                      //
             printf( "error: %d.\n", WSAGetLastError() );        //  画面表示                                      //
             closesocket( sock );                                //  ソケット解放                                  //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         _snprintf_s( msg, sizeof(msg), 8, "%s", "Hello.\n" );   //  メッセージ編集                                //
         index = send( sock, msg, strlen(msg), 0 );              //  メッセージを送信する                          //
         if( SOCKET_ERROR == index )                             //  メッセージ送信に失敗したか                    //
         {                                                       //  メッセージ送信に失敗した場合                  //
             printf( "failed to send.\n" );                      //  画面表示                                      //
             printf( "error: %d\n", WSAGetLastError() );         //  画面表示                                      //
             shutdown( sock, 2 );                                //  送受信中止                                    //
             closesocket( sock );                                //  ソケット解放                                  //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
                                                                 //                                                //
         recvBytes = recv( sock, msg, sizeof(msg), 0 );          //  メッセージ受信を試行                          //
         if( SOCKET_ERROR == recvBytes )                         //  メッセージ受信に失敗したか                    //
         {                                                       //  メッセージ受信に失敗した場合                  //
             printf( "failed to receive.\n" );                   //  画面表示                                      //
             printf( "error: %d\n", WSAGetLastError() );         //  画面表示                                      //
             closesocket( sock );                                //  ソケット解放                                  //
             rtnCod = RET_NG;                                    //  リターンにNGを設定                            //
             break;                                              //  処理終了                                      //
         }                                                       //                                                //
         printf( "recvBytes = %d.\n\n", recvBytes );             //  画面表示                                      //
         msg[recvBytes] = '\0';                                  //  文字列終端の付与                              //
         printf( "client rec: %s\n", msg );                      //  画面表示                                      //
     }                                                           //                                                //
                                                                 //                                                //
     shutdown( sock, 2 );                                        //  送受信中止                                    //
     closesocket( sock );                                        //  ソケット解放                                  //
                                                                 //                                                //
     _endthreadex( rtnCod );                                     //  スレッド処理終了                              //
     return( rtnCod );                                           //  リターンを返して終了                          //
 }                                                               //                                                //
 //*Client Receiver Thread *************************************//*  クライアント受信待ちスレッド作成処理          */
 /* Multi Thread Constructor ***********************************//*  マルチスレッドコンストラクタ                  */
 cl_mt::cl_mt ()                                                 //  コンストラクタ                                //
     : vc_kill_threads( IND_FALSE ),                             //  スレッド終了指示の初期化                      //
       vc_threadId( NULL )                                       //  スレッド識別子の初期化                        //
 {                                                               //                                                //
 }                                                               //                                                //
 //*Multi Thread Constructor ***********************************//*  マルチスレッドコンストラクタ                  */
 /* Multi Thread Initializer ***********************************//*  マルチスレッド初期化処理                      */
 char cl_mt::init( void )                                        //                                                //
 {                                                               //                                                //
     char rtnCod = RET_OK;                                       //  リターンコード                                //
                                                                 //                                                //
     for ( ; ; )                                                 //  無限ループ                                    //
     {                                                           //                                                //
         create_thread();                                        //  スレッド生成依頼                              //
         SetEvent( vc_events[1] );                               //  イベント1(報知)をシグナル状態にする           //
                                                                 //                                                //
         break;                                                  //  処理終了                                      //
     }                                                           //                                                //
                                                                 //                                                //
     return( rtnCod );                                           //  リターンコードを返して終了                    //
 }                                                               //                                                //
 //*Multi Thread Initializer ***********************************//*  マルチスレッド初期化処理                      */
 /* Destroy Threads ********************************************//*  スレッド解放処理                              */
 char cl_mt::destroyThreads( void )                              //                                                //
 {                                                               //                                                //
     char rtnCod = RET_OK;                                       //  終了コード                                    //
                                                                 //                                                //
     vc_kill_threads = IND_TRUE;                                 //  スレッド終了指示を指示ありに更新する          //
     SetEvent( vc_events[1] );                                   //  イベント1(報知)をシグナル状態にする           //
     Sleep( 25 );                                                //  安全なスレッド解放のため                      //
     CloseHandle( vc_handle );                                   //  ハンドルクローズ                              //
                                                                 //                                                //
     return( rtnCod );                                           //  正常終了                                      //
 }                                                               //                                                //
 //*Destroy Server's Threads ***********************************//*  サーバスレッド解放処理                        */
 /* Multi Thread Deconstructor *********************************//*  マルチスレッドデコンストラクタ                */
 cl_mt::~cl_mt ()                                                //  デストラクタ                                  //
 {                                                               //                                                //
     CloseHandle( vc_events[0] );                                //  イベントハンドルを閉じる                      //
     CloseHandle( vc_events[1] );                                //  イベントハンドルを閉じる                      //
 }                                                               //                                                //
 //*Multi Thread Deconstructor *********************************//*  マルチスレッドデコンストラクタ                */
 /* Client Constructor *****************************************//*  クライアントコンストラクタ                    */
 cl_client::cl_client ()                                         //  コンストラクタ                                //
 {                                                               //                                                //
     int vn_pid = GetCurrentProcessId();                         //  プロセスID取得                                //
 //    TCHAR eventName[16];                                        //  イベント名編集用                              //
     char eventName[16];                                         //  イベント名編集用                              //
                                                                 //                                                //
     printf( "vn_pid = %d\n\n", vn_pid );                        //  画面表示                                      //
     _sntprintf_s( eventName, _countof(eventName), 16, _T("%d"), vn_pid ); //  イベント名を編集                    //
                                                                 //  イベントオブジェクト作成                      //
     vc_events[0] = CreateEvent( NULL,                           //  継承時SECURITY_ATTRIBUTES構造体ポインタ       //
                                   TRUE,                         //  TRUE=手動、FALSE=自動リセットオブジェクト     //
                                   FALSE,                        //  TRUE=シグナル状態、FALSE=非シグナル状態       //
                                   _T("TH_CL") );                //  イベントオブジェクト名                        //
     vc_events[1] = CreateEvent( NULL, TRUE, FALSE, eventName ); //  イベントオブジェクト作成 *OS内での混乱回避*   //
 }                                                               //                                                //
 //*Client Constructor *****************************************//*  クライアントコンストラクタ                    */
 /* Client Deconstructor ***************************************//*  クライアントデコンストラクタ                  */
 cl_client::~cl_client ()                                        //  デストラクタ                                  //
 {                                                               //                                                //
 }                                                               //                                                //
 //*Client Deconstructor ***************************************//*  クライアントデコンストラクタ                  */
 /* Server Constructor *****************************************//*  サーバコンストラクタ                          */
 cl_server::cl_server ()                                         //  コンストラクタ                                //
     : vc_sv_sessionId( ZERO )                                   //  セッション指示子の初期化                      //
 {                                                               //                                                //
     int cnt = ZERO;                                             //  ループカウンタ                                //
                                                                 //                                                //
     for( ; MAX_SESSIONS + 1 > cnt; cnt++ )                      //  最大セッション数+1回繰返す                    //
     {                                                           //                                                //
         vc_sv_sessions[cnt] = NULL;                             //  ソケットを初期化                              //
     }                                                           //                                                //
                                                                 //  イベントオブジェクト作成                      //
     vc_events[0] = CreateEvent( NULL,                           //  継承時SECURITY_ATTRIBUTES構造体ポインタ       //
                                   TRUE,                         //  TRUE=手動、FALSE=自動リセットオブジェクト     //
                                   FALSE,                        //  TRUE=シグナル状態、FALSE=非シグナル状態       //
                                   _T("TH_SV") );                //  イベントオブジェクト名                        //
     vc_events[1] = CreateEvent( NULL, TRUE, FALSE, _T("RECV_SV") ); //  イベントオブジェクト作成                  //
 }                                                               //                                                //
 //*Server Constructor *****************************************//*  サーバコンストラクタ                          */
 /* Server Deconstructor ***************************************//*  サーバデコンストラクタ                        */
 cl_server::~cl_server ()                                        //  デストラクタ                                  //
 {                                                               //                                                //
 }                                                               //                                                //
 //*Server Deconstructor ***************************************//*  サーバデコンストラクタ                        */
 /* Create Client Thread ***************************************//*  クライアントスレッド作成処理                  */
 char cl_client::create_thread( void )                           //                                                //
 {                                                               //                                                //
     char rtnCod = RET_OK;                                       //  終了コード                                    //
                                                                 //                                                //
     for( ; ; )                                                  //  無限ループ                                    //
     {                                                           //                                                //
         if( NULL != vc_threadId )                               //  スレッドが既に存在しているか                  //
         {                                                       //  スレッドが既に存在している場合                //
             SetEvent( vc_events[1] );                           //  イベント1(報知)をシグナル状態にする           //
         }                                                       //                                                //
         else                                                    //  スレッドがまだ存在していない場合              //
         {                                                       //                                                //
             vc_handle =                                         //  スレッド新規作成                              //
                 (HANDLE)_beginthreadex( NULL,                   //  セキュリティ構造体へのポインタ or NULL        //
                                         RET_OK,                 //  スタックサイズ                                //
                                         &cl_client::th_receiver, //  スレッド関数のアドレス                       //
                                         NULL,                   //  引数ポインタは今回はNULLで                    //
                                         RET_OK,                 //  0はすぐ実行、CREATE_SUSPENDEDは一時停止状態で //
                                         &(vc_threadId) );       //  スレッド識別子 or NULL                        //
         }                                                       //                                                //
                                                                 //                                                //
         break;                                                  //  処理終了                                      //
     }                                                           //                                                //
                                                                 //                                                //
     return( rtnCod );                                           //  正常終了                                      //
 }                                                               //                                                //
 //*Create Client Thread ***************************************//*  クライアントスレッド作成処理                  */
 /* Create Server Thread ***************************************//*  サーバスレッド作成処理                        */
 char cl_server::create_thread( void )                           //                                                //
 {                                                               //                                                //
     char rtnCod = RET_OK;                                       //  終了コード                                    //
                                                                 //                                                //
     for( ; ; )                                                  //  無限ループ                                    //
     {                                                           //                                                //
         if( NULL != vc_threadId )                               //  スレッドが既に存在しているか                  //
         {                                                       //  スレッドが既に存在している場合                //
             SetEvent( vc_events[1] );                           //  イベント1(報知)をシグナル状態にする           //
         }                                                       //                                                //
         else                                                    //  スレッドがまだ存在していない場合              //
         {                                                       //                                                //
             vc_handle =                                         //  スレッド新規作成                              //
                 (HANDLE)_beginthreadex( NULL,                   //  セキュリティ構造体へのポインタ or NULL        //
                                         RET_OK,                 //  スタックサイズ                                //
                                         &cl_server::th_receiver, //  スレッド関数のアドレス                       //
                                         NULL,                   //  引数ポインタは今回はNULLで                    //
                                         RET_OK,                 //  0はすぐ実行、CREATE_SUSPENDEDは一時停止状態で //
                                         &(vc_threadId) );       //  スレッド識別子 or NULL                        //
         }                                                       //                                                //
                                                                 //                                                //
         break;                                                  //  処理終了                                      //
     }                                                           //                                                //
                                                                 //                                                //
     return( rtnCod );                                           //  正常終了                                      //
 }                                                               //                                                //
 //*Create Server Thread ***************************************//*  サーバスレッド作成処理                        */

動作確認
 >cl.exe seqSv.cpp
 Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
 Copyright (C) Microsoft Corporation.  All rights reserved.
 
 seqSv.cpp
 Microsoft (R) Incremental Linker Version 9.00.30729.01
 Copyright (C) Microsoft Corporation.  All rights reserved.
 
 /out:seqSv.exe
 seqSv.obj
 
 >seqSv.exe 3 localhost
 vn_pid = 5564
 
 it takes 16 msec.
 
 This is client's thread.
 
 This is server's thread.
 
 waiting for clients.
 
 a client accepted: 127.0.0.1
 
 session ID: 0
 
 sessions: 1
 
 go next selection.
 
 recvBytes = 7.
 
 server rec: Hello.
 
 go next selection.
 
 recvBytes = 7.
 
 client rec: Hello.
 
 
 This is client's thread.
 
 Client's thread killed.
 
 recvBytes = 0.
 
 session closed.
 
 go next selection.
 
 go next selection.
 
 This is server's thread.
 
 Server's thread killed.
 
 
 
 >

*** 修正履歴 [#ua9ab7c0]
~

*** 課題 [#wae2c1e5]
~

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS