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