概要
作業目的
DXライブラリを利用してSocketクライアントを作成します。
環境・前提条件
本件手順では、以下Windows環境にMicrosoft Visual Studioがインストールされている前提とします。
- エディション:Microsoft Windows 10 Pro
- システムの種類:64 ビット オペレーティング システム、x64 ベース プロセッサ
- バージョン:22H2
- OSビルド 19045.4651
- エクスペリエンス:Windows Feature Experience Pack 1000.19060.1000.0
- Microsoft Visual Studio Community 2022 (64 ビット) :Version 17.9.7
- DXライブラリ Windows版 VisualStudio( C++ )用:Ver 3.24d
- (2024年7月21日現在)
参考ページ
その他の参考となるページは以下に記載しています。
DXライブラリ準備
DXライブラリの事前設定
下記ページから、DXライブラリの設定準備を進めてください。
- Visual Studio Community 2022 を使用した場合のDXライブラリの使い方
- 以後はプロジェクト名を「dxtest」、ソース名を「dxtest.cpp」として説明します。
DXライブラリでSocket処理を利用する場合の注意点
Socket処理のサンプル
下記ページにサンプルがあります。
送信データサイズの解除
事前に"SetUseDXNetWorkProtocol"関数を実行して、無効化する必要があります。
SetUseDXNetWorkProtocol( FALSE );
Socketクライアントの作成
処理概要
Socketクライアントとしてメッセージを送信するアプリケーションを作成します。
プログラムソース
[手順1.]ソースの作成
以下のソースについてコピー&ペーストします。
保存する場合にはテキストファイルを以下の形式としています。
(テキストファイルの仕様)
- 改行コード:SJIS
- 改行コード:CR+LF
dxtest.cpp
/* ----------------------------------------------------------------------------------------------
*
* プログラム概要 : DXライブラリ用Socket接続
* バージョン : 1.0.0.0
* プログラム名 : dxtest.exe
* ファイル名 : dxtest.cpp
* 処理概要 : メイン処理
* Ver1.0.0.0作成日 : 2024/07/21 10:32:37
* 最終更新日 : 2024/07/21 10:32:37
*
* Copyright (c) 2023-2024 Techmilestone, All rights reserved.
*
* ---------------------------------------------------------------------------------------------- */
#include "DxLib.h"
// ----------------------------------------
// グローバル変数定義
// ----------------------------------------
// ----------------------------------------
// 変数初期化(フレーム処理)
// ----------------------------------------
// フレーム処理用定数
static const int SAMPLE_FRAME_COUNT = 60; // フレームのサンプル数
static const int FPS = 60; // 想定のFPS値 (待ち時間の算出用)
// FPS算出用変数(フレーム定義)
static int frame_count; // サンプルフレームのカウンタ数
static int total_frame_count; // 処理したフレームの合計数
// FPS算出用変数(時間定義)
static int checkpoint_time; // 定点時刻(チェックポイントごとの時刻)
static int wait_time; // 待ち時間(Sleep関数を利用するために単位はミリ秒)
// FPS算出用変数(FPS数)
static float ave_fps; // 実測のFPS値
// ----------------------------------------
// 変数初期化(マウス処理)
// ----------------------------------------
// マウス処理情報
static int msx; // X座標
static int msy; // Y座標
static int get_mouse_input; // マウスの押した状態取得
static unsigned int get_button[8]; // ボタンの押した状態
static int wheel_rot_vol; // ホイールの回転量
// ----------------------------------------
// 変数初期化(画像処理)
// ----------------------------------------
// 画像ハンドル
static int pic_handle; // 背景用画像
// ----------------------------------------
// 変数初期化(Socket処理)
// ----------------------------------------
static int net_handle; // ネットワークハンドル
static char rcv_buf[1024]; // 受信用バッファ
static char snd_buf[1024]; // 送信用バッファ
// ----------------------------------------
// フレーム初期化
// ----------------------------------------
int WindowFrameInit(){
// Log.txtの出力抑止
SetOutApplicationLogValidFlag(FALSE);
// ウインドウモードにする
// DxLib_Initより前に行う
if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK ) {
// 異常終了
return -1;
}
// ウィンドウサイズ変更
SetGraphMode( 1024 , 768 , 32 );
SetWindowSize( 1024 , 768 );
// ウインドウがアクティブではない状態でも処理を続行する
SetAlwaysRunFlag(TRUE);
// 2つ以上同時に起動できるかどうかを設定する。
SetDoubleStartValidFlag(TRUE);
// マウス表示オン
SetMouseDispFlag(TRUE);
// 正常終了
return 0;
}
// ----------------------------------------
// DX表示ライブラリ初期化
// ----------------------------------------
int CustomDxlibInit(){
// DXライブラリ初期化
if (DxLib_Init() != 0){
// 異常終了
return -1;
}
// 描画先を裏画面に設定
SetDrawScreen(DX_SCREEN_BACK);
// 画像ハンドル
pic_handle = LoadGraph("bmp/back.bmp"); // 画像のロード
// 正常終了
return 0;
}
// ----------------------------------------
// DX表示ライブラリ終了処理
// ----------------------------------------
void CustomDxlibEnd(){
DxLib_End(); // DXライブラリ使用の終了処理
}
// ----------------------------------------
// Fps算出処理の初期化
// ----------------------------------------
void FpsParamInit(){
// 変数初期化
ave_fps = 0; // ave_fps初期化
frame_count = 0; // frame_count初期化
total_frame_count = 0; // total_frame_count初期化
// 最初フレームの「定点時刻(checkpoint_time)」定義
checkpoint_time = GetNowCount();
}
// ----------------------------------------
// 定点時刻(checkpoint_time)の更新、平均Fps算出
// ----------------------------------------
void FpsUpdate(){
// 変数定義
int tmp_now_time; // 現在時刻
// サンプルフレーム数に達した場合の内部処理
// 「定点時刻(checkpoint_time)」の更新、「平均ave_fps」算出
if( frame_count == SAMPLE_FRAME_COUNT ){
// 現在の時間の取得
tmp_now_time = GetNowCount();
// 「平均ave_fps」算出処理
ave_fps = (float)SAMPLE_FRAME_COUNT*1000.f / (tmp_now_time - checkpoint_time);
// 「フレームのカウンタ数」の初期化
frame_count = 0;
// SAMPLE_FRAME_COUNTごとに「定点時刻」を更新
checkpoint_time = tmp_now_time;
}
// 「フレームのカウンタ数」の加算
frame_count++;
// 「合計フレームのカウンタ数」の加算
total_frame_count++;
}
// ----------------------------------------
// FPSウエイト処理
// ----------------------------------------
void FpsWait(){
// 現在時刻と「定点時刻(checkpoint_time)」との差分時間を算出
// それから待ち時間(wait_time)を算出
wait_time = ( frame_count*1000 / FPS ) - (GetNowCount() - checkpoint_time); // frame_countからの理論時刻と実機からの現在時間との差分を算出する
// ウエイト処理
if( wait_time > 0 ){
Sleep(wait_time); // wait_timeの時間(ミリ秒)だけ待機を行う
}
}
// ----------------------------------------
// 表示処理
// ----------------------------------------
void CustomDxlibDraw(){
// 画面を消す
ClearDrawScreen();
// 背景表示
DrawGraph( 0, 0, pic_handle, TRUE );
// 文字列表示
DrawFormatString( 5, 0, GetColor(255,255,255), "受信メッセージ:%s", rcv_buf);
DrawFormatString( 5, 17, GetColor(255,255,255), "実測FPS値:%.1f", ave_fps);
// 裏画面を表画面に反映
ScreenFlip();
}
// ----------------------------------------
// socket初期化
// ----------------------------------------
int CustomSocketInit(){
// 変数定義
IPDATA ip; // 接続用IPアドレスデータ
// DXライブ独自のsocket仕様の機能を使用しない
SetUseDXNetWorkProtocol( FALSE );
// IPアドレスを設定
ip.d1 = 127 ;
ip.d2 = 0 ;
ip.d3 = 0 ;
ip.d4 = 1 ;
// 通信を確立
net_handle = ConnectNetWork( ip, 11600 ) ;
// ハンドルの正常性確認
if( net_handle == -1 ){
// 異常終了
return -1;
}else{
// データ送信
sprintf_s(snd_buf,"接続要求\n");
NetWorkSend(net_handle, snd_buf, lstrlen(snd_buf)) ;
// 正常終了
return 0;
}
}
// ----------------------------------------
// socket終了処理
// ----------------------------------------
void CustomSocketEnd(){
// ネットワークハンドルの解放
CloseNetWork(net_handle);
}
// ----------------------------------------
// データ送受信
// ----------------------------------------
void CustomSocketRecSnd(){
// 変数定義
int data_size; // 受信データ時のデータサイズ
// 取得していない受信データ量を得る
data_size = GetNetWorkDataLength(net_handle);
// 受信データ量が0より大きい場合
if( data_size > 0 ){
// バッファクリア
memset(rcv_buf, 0, sizeof(rcv_buf));
// 受信したデータをバッファに取得
NetWorkRecv(net_handle, rcv_buf, sizeof(rcv_buf));
// サーバ側にデータ送信
sprintf_s(snd_buf,"受信完了\n");
NetWorkSend(net_handle, snd_buf, lstrlen(snd_buf));
}
}
// ----------------------------------------
// メイン処理
// ----------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
// ----------------------------------------
// 事前処理
// ----------------------------------------
// Windows画面の事前処理
if (WindowFrameInit() != 0){
// ダイアログの出力
MessageBox( NULL, "異常終了 ChangeWindowMode", "警告", MB_OK );
return -1;
}
// DXライブラリ初期化
if (CustomDxlibInit() != 0){
// ダイアログの出力
MessageBox( NULL, "異常終了 DxLib_Init", "警告", MB_OK );
return -1;
}
// FPS処理初期化
if (CustomSocketInit() != 0){
// ダイアログの出力
MessageBox( NULL, "異常終了 Socket_Init", "警告", MB_OK );
return -1;
}
// FPS処理初期化
FpsParamInit();
// ----------------------------------------
// メイン処理(ループ処理)
// ----------------------------------------
// 終了処理がされるまで、ループ処理
while( ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0 ){
// 関数処理
CustomSocketRecSnd(); // socketデータの送受信
FpsUpdate(); // checkpoint_time更新、平均Fps算出
CustomDxlibDraw(); // 表示処理
FpsWait(); // ウエイト処理
}
// ----------------------------------------
// 終了処理
// ----------------------------------------
// socket終了処理
CustomSocketEnd();
// DXライブラリ終了処理
CustomDxlibEnd();
// 正常終了
return 0;
}
/* ----------------------------------------------------------------------------------------------
* ソース終了
* ---------------------------------------------------------------------------------------------- */
[手順2.]ソースのビルドを行う。
Visual Studio Communityを利用してビルドを行ってください。
Socketクライアントの機能説明
はじめに
Socket利用のために、実装が必要となるDXライブラリの関数を記載します。
1.変数定義
以下の変数を定義します
static int net_handle; // ネットワークハンドル
static char rcv_buf[1024]; // 受信用バッファ
static char snd_buf[1024]; // 送信用バッファ
2.サーバに接続
connect関数でリモートソケット(サーバ側ソケット)に接続します
// DXライブ独自のsocket仕様の機能を使用しない
SetUseDXNetWorkProtocol( FALSE );
// IPアドレスを設定
ip.d1 = 127 ;
ip.d2 = 0 ;
ip.d3 = 0 ;
ip.d4 = 1 ;
// 通信を確立
net_handle = ConnectNetWork( ip, 11600 ) ;
3.サーバにデータを送信
NetWorkSend関数で接続済みサーバのソケットにデータを送信します。
// データ送信
sprintf_s(snd_buf,"接続要求\n");
NetWorkSend(net_handle, snd_buf, lstrlen(snd_buf)) ;
4.サーバからデータを受信
サーバからのデータ受信を検知します。
// 取得していない受信データ量を得る
data_size = GetNetWorkDataLength(net_handle);
// 受信データ量が0より大きい場合
if( data_size > 0 ){
// バッファクリア
memset(rcv_buf, 0, sizeof(rcv_buf));
// 受信したデータをバッファに取得
NetWorkRecv(net_handle, rcv_buf, sizeof(rcv_buf));
}
参考情報
動作確認
事前処理:「TCP/IPテストツール」のインストール
以下サイトからSocketクライアント用フリーツールを取得します。
上記のアプリケーションをインストールします。
動作確認:接続確認
以下のとおりにクライアントがサーバからのメッセージを受信しています。
[手順1.]「TCP/IPテストツール」を起動します。
[手順2.]ビルドしたアプリケーションを起動します。
[手順3.]「TCP/IPテストツール」でデータを受信したことを確認します。
動作確認:データ送信
[手順1.]「TCP/IPテストツール」でデータを送信します。
[手順2.]ビルドしたアプリケーションがデータを受信したことを確認します。
以上