C++/ソケットサンプル2(Windowsサーバ・クライアント) †Windows上でサーバ及びクライアントとして動作するサンプルを解説する。 C++/ソケットサンプル1(Linuxサーバ) 制約 †サンプルとして、ホスト名"clove.la"でアクセスできること。 #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. > 修正履歴 †課題 † |