ソケットサンプル1(Linuxサーバ) †Linux上でサーバとして動作するサンプルを解説する。 C++/ソケットサンプル2(Windowsサーバ・クライアント) 制約 †サンプルとして、ホスト名"clove.la"でアクセスできること。 #include <stdio.h> // stdioをインクルード // #include <stdlib.h> // stdlibをインクルード // #include <sys/types.h> // sys/typesをインクルード // #include <sys/time.h> // sys/timeをインクルード // #include <sys/socket.h> // sys/socketをインクルード // #include <netinet/in.h> // netinet/inをインクルード // #include <unistd.h> // unistdをインクルード // #include <netdb.h> // netdbをインクルード // #include <arpa/inet.h> // arpa/inetをインクルード // #include <string.h> // stringをインクルード // #include <pthread.h> // pthreadをインクルード // //#include <semaphore.h> // semaphoreをインクルード // // // #define BUFF_SIZE_MERE 1024 // 汎用バッファサイズ // //#define SV_PORT 4519 // 使用ポート // #define SV_PORT 57891 // 使用ポート // #define MAX_CONNS 19 // 最大セッション数 // // // const int ADDR_SIZE = sizeof(struct sockaddr_in); // sockaddr_inサイズ // // // static int vc_kill_th_sv = 0; // サーバスレッド終了指示 // // // void* th_sv( void* vd_data ); // サーバ処理 // void* th_cl( void* vd_data ); // クライアント処理 // // // /* Main *******************************************************//* 起動処理 */ int main( void ) // メイン関数 // { // // int rtnCod = 0; // リターンコード // pthread_t svid; // サーバスレッドID // // pthread_t clid; // クライアントスレッドID // // // pthread_create( &svid, NULL, th_sv, NULL ); // サーバスレッド生成 // // pthread_create( &clid, NULL, th_cl, NULL ); // クライアントスレッド生成 // // // // // pthread_join( svid, NULL ); // サーバスレッド終了を待つ // // pthread_join( clid, NULL ); // クライアントスレッド終了を待つ // // // getchar(); // 終了確認用 // vc_kill_th_sv = 1; // サーバスレッド終了指示 // pthread_join( svid, NULL ); // サーバスレッド終了を待つ // // // return( rtnCod ); // 処理終了 // } // // //*Main *******************************************************//* 起動処理 */ /* Server Thread **********************************************//* サーバスレッド作成処理 */ void* th_sv( void* vd_data ) // // { // // int index = 0; // 内部処理判定用 // static int sessionNum = 0; // セッション数 // static int sessionIndicator; // セッションID取得用 // int sv_sock; // サーバ用ソケット // int cl_sock[MAX_CONNS]; // クライアント用ソケット // int tmp_sock; // 一時使用ソケット // int clAddrLen; // クライアント側アドレス文字列長 // int cnt; // ループカウンタ // // // fd_set fds; // ファイルディスクリプタセット // fd_set fds_bk; // ファイルディスクリプタセット(保持用) // struct timeval timeVal; // タイムアウト時間指定用 // // // struct sockaddr_in srcAddr; // ソースアドレス // // struct sockaddr_in dstAddr; // 宛先アドレス // // // char strBuf[BUFF_SIZE_MERE] = ""; // 文字列用バッファ // // // struct hostent *host; // ホスト関連情報 // unsigned int** addrRoot; // ホストアドレス解決用 // int recvBytes; // 受信バイト数確認用 // // // host = gethostbyname( "clove.la" ); // ホスト関連情報取得 // // // memset( cl_sock, 0, sizeof(cl_sock) ); // ソースアドレス領域初期化 // // // for( ; ; ) // 無限ループ // { // // if( NULL == host ) // 無効なホストか // { // 無効なホストなら // printf( "unknown host.\n" ); // 画面表示 // break; // 処理中止 // } // // // // addrRoot = (unsigned int **)host->h_addr_list; // ホストアドレス解決 // if( NULL == *addrRoot ) // アドレス解決に失敗したか // { // アドレス解決に失敗した場合 // printf( "failed to resolve host name.i\n" ); // 画面表示 // break; // 処理中止 // } // // // // timeVal.tv_sec = 10; // タイムアウト秒数 // timeVal.tv_usec = 0; // タームアウトマイクロ秒数 // // // memset( &srcAddr, 0, sizeof(srcAddr) ); // ソースアドレス領域初期化 // // // srcAddr.sin_port = htons( SV_PORT ); // ポート指定 // srcAddr.sin_family = AF_INET; // コネクション型アドレスファミリー // srcAddr.sin_addr.s_addr = htonl( INADDR_ANY ); // 全アドレス許容 // // // sv_sock = socket( AF_INET, SOCK_STREAM, 0 ); // サーバ用ソケット生成 // index = bind( sv_sock, (struct sockaddr *) &srcAddr, ADDR_SIZE ); // ポート関連付け // if( -1 == index ) // bindに失敗したか // { // bindに失敗した場合 // printf( "failed to bind.\n" ); // 画面表示 // close( sv_sock ); // ソケットクローズ // } // // // // index = listen( sv_sock, MAX_CONNS ); // 接続待ち // if( -1 == index ) // listenに失敗したか // { // listenに失敗した場合 // printf( "time out listening.\n" ); // 画面表示 // close( sv_sock ); // ソケットクローズ // } // // // // clAddrLen = sizeof(srcAddr); // アドレス文字列長取得 // // // FD_ZERO( &fds_bk ); // FDS初期化 // FD_SET( sv_sock, &fds_bk ); // FDS登録 // // // for( ; ; ) // 真・無限ループ // { // // if( 0 != vc_kill_th_sv ) // スレッド終了指示が指示ありか // { // スレッド終了指示が指示ありなら // break; // 真・無限ループを抜けた先で処理終了 // } // // // // memcpy( &fds, &fds_bk, sizeof(fd_set) ); // 保持していたFDSから複製 // timeVal.tv_sec = 10; // タイムアウト秒数 // timeVal.tv_usec = 0; // タームアウトマイクロ秒数 // // // index = select( MAX_CONNS + 1, &fds, NULL, NULL, &timeVal ); // コネクション通知待ち // if( 0 == index ) // タイムアウトしたか // { // タイムアウトした場合 // printf( "waiting for clients.\n" ); // 画面表示 // // memcpy( &fds, &fds_bk, sizeof(fd_set) ); // 保持していたFDSから複製 // continue; // 再select // } // // // // if( FD_ISSET( sv_sock, &fds ) ) // コネクション通知があるか // { // コネクション通知がある場合 // // cl_sock[sessionNum] = // コネクション接続を試行 // // accept( sv_sock, (struct sockaddr *) &srcAddr, (socklen_t*)ADDR_SIZE ); // // tmp_sock = // コネクション接続を試行 // // accept( sv_sock, (struct sockaddr *) &srcAddr, (socklen_t*)&ADDR_SIZE ); // // accept( sv_sock, (struct sockaddr *) &srcAddr, (socklen_t*)&clAddrLen ); // // if( -1 == tmp_sock ) // acceptに失敗したか // { // acceotに失敗した場合 // printf( "time out accepting. sessionNum = %d\n", sessionNum ); // 画面表示 // } // // else // acceptに成功した場合 // { // // if( MAX_CONNS == sessionNum ) // セッション数が上限に達したか // { // セッション数が上限に達した場合 // printf( "session full.\n\n" ); // 画面表示 // // _snprintf_s( strBuf, sizeof(strBuf), 16, "%s", "server busy.\n\n" ); // メッセージ編集 // snprintf( strBuf, 16, "%s", "server busy.\n\n" ); // メッセージ編集 // send( tmp_sock, strBuf, strlen(strBuf), 0 ); // セッション数最大を通知 // shutdown( tmp_sock, 2 ); // ソケットを明示的に停止 // close( tmp_sock ); // ソケットをクローズ // sessionNum--; // セッション数をデクリメント // continue; // 再select // } // // // // for( sessionIndicator = 0; // すべてのセッションIDについて // MAX_CONNS > sessionIndicator; sessionIndicator++ ) // // { // // if( 0 == cl_sock[sessionIndicator] ) // ソケットが未接続か // { // ソケットが未接続なら // cl_sock[sessionIndicator] = tmp_sock; // セッションを保持 // printf( "session ID: %d\n\n", sessionIndicator ); // 画面表示 // FD_SET( tmp_sock, &fds_bk ); // FDS登録 // sessionNum++; // セッション数をインクリメント // printf( "sessions: %d\n\n", sessionNum ); // 画面表示 // break; // セッションを保持したらループを抜ける // } // // } // // } // // } // // // // for( cnt = 0; MAX_CONNS > cnt; cnt++ ) // すべての個別セッションについて // { // // if( FD_ISSET(cl_sock[cnt], &fds) ) // 情報が通知されているか確認する // { // // tmp_sock = cl_sock[cnt]; // 対象個別ソケット操作用 // recvBytes = recv( tmp_sock, strBuf, sizeof(strBuf), 0 ); // メッセージ受信を試行 // printf( "recvBytes = %d.\n\n", recvBytes ); // 画面表示 // if( -1 == recvBytes ) // 受信エラーか // { // // // errInd = WSAGetLastError(); // エラー番号を保持 // // if( WSAECONNRESET == errInd ) // エラー番号がセッションクローズか // // { // エラー番号がセッションクローズなら // // printf( "session closed.\n\n" ); // 画面表示 // // } // // // else // エラー番号がセッションクローズ以外なら // // { // // // printf( "failed to receive.\n" ); // 画面表示 // // printf( "error: %d\n", errInd ); // 画面表示 // // } // // printf( "failed to receive.\n" ); // 画面表示 // FD_CLR( tmp_sock, &fds_bk ); // FDSからソケット解放 // cl_sock[cnt] = 0; // 保持ソケットを解放 // close( tmp_sock ); // ソケット解放 // sessionNum--; // セッション数をデクリメント // continue; // 次の個別セッションに進む // } // // else if( 0 == recvBytes ) // 受信バイト数がZEROか // { // 受信バイト数がZEROなら // printf( "session closed.\n\n" ); // 画面表示 // FD_CLR( tmp_sock, &fds_bk ); // FDSからソケット解放 // cl_sock[cnt] = 0; // 保持ソケットを解放 // close( tmp_sock ); // ソケット解放 // sessionNum--; // セッション数をデクリメント // continue; // 以降のループ処理をスキップ // } // // strBuf[recvBytes] = '\0'; // 文字列終端の付与 // printf( "server rec: %s\n", strBuf ); // 画面表示 // // // index = send( tmp_sock, strBuf, strlen(strBuf), 0 ); // メッセージ送信 // if( -1 == index ) // メッセージ送信に失敗したか // { // メッセージ送信に失敗した場合 // printf( "failed to send.\n" ); // 画面表示 // FD_CLR( tmp_sock, &fds_bk ); // FDSからソケット解放 // cl_sock[cnt] = 0; // 保持ソケットを解放 // close( tmp_sock ); // ソケット解放 // shutdown( tmp_sock, 2 ); // 送受信中止 // close( tmp_sock ); // ソケット解放 // sessionNum--; // セッション数をデクリメント // continue; // 以降のループ処理をスキップ // } // // } // // } // // } // // // // break; // ループを抜ける // } // // // // shutdown( sv_sock, 2 ); // 送受信中止 // close( sv_sock ); // ソケット解放 // // // return( vd_data ); // 処理終了 // } // // //*Server Thread **********************************************//* サーバスレッド作成処理 */ /* Client Thread **********************************************//* クライアントスレッド作成処理 */ void* th_cl( void* vd_data ) // // { // // // int cnt = 0; // ループカウンタ // // // return( vd_data ); // 処理終了 // } // // //*Client Thread **********************************************//* クライアントスレッド作成処理 */ 動作確認 # g++ -Wall seqSv.cpp -lpthread -L/usr/lib # ./a.out session ID: 0 sessions: 1 recvBytes = 7. server rec: Hello. recvBytes = 0. session closed. 修正履歴 †課題 †クライアントとしての動作は実装していない。 |