FrontPage

C++/ソケットサンプル2(Windowsサーバ・クライアント)

Windows上でサーバ及びクライアントとして動作するサンプルを解説する。
引数1に(1: クライアント、2: サーバ、3: 両方)を指定。
引数2に接続先ホスト名を指定。

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

制約

サンプルとして、ホスト名"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.



>

修正履歴


課題



トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-03-07 (水) 23:49:48 (4432d)