クライアント/サーバ:PIPE 1本で双方向+EVENT

2017-02-03 :  PCクリニック
Python、C言語、Perl、グルコサミン、Firefox
前(2017-02-01)の記事「クライアント/サーバ:PIPE 1本で双方向通信」に続いて、
イベントは無くても良さそう(?)だったが、
正統?“ハンドシェイク通信”とすべく、EVENT 同期を追加した。


その前に、
“プロトタイプ?”宣言をダラダラ書きたくないので、
サブプログラム化した:
----- cdef_PIPE_Event_SUB.lua
charA = |s| ffi.cast( 'char*', s )
C = ffi.C; band = bit.band ----- コード 省略形

Buf = ffi.new('uint8_t[4097]') ----- 取り敢えずバッファ確保
nIO = ffi.new('uint32_t[1]') ----- 実I/Oバイト数

ffi.cdef[[
typedef unsigned int DWORD;

void Sleep( int MilliSeconds );

// ----- PIPE 用
int CreateNamedPipeA(
char* lpName, // パイプ名
DWORD dwOpenMode, // パイプを開くモード
DWORD dwPipeMode, // パイプ固有のモード
DWORD nMaxInstances, // インスタンスの最大数
DWORD nOutBufferSize, // 出力バッファのサイズ
DWORD nInBufferSize, // 入力バッファのサイズ
DWORD nDefaultTimeOut, // タイムアウトの間隔
int lpSecurityAttributes ); // セキュリティ記述子

int ConnectNamedPipe( int hNamedPipe, int lpOverlapped );

int CreateFileA(
char* pszFileName, // ファイル名
DWORD dwAccess, // アクセス指定
DWORD dwShare, // 共有方法
int psa, // セキュリティ属性
DWORD dwCreatDisposition, // 動作指定
DWORD dwFlagsAndAttributes, // フラグと属性
int hTemplate ); // テンプレートファイル

int ReadFile( int hFile, char* lpBuffer,
DWORD nNumberOfBytesToRead,
void* lpNumberOfBytesRead,
int lpOverlapped );

int WriteFile( int hFile, char* pBuffer,
DWORD nNumberOfBytesToWrite,
void* lpNumberOfBytesWritten,
int lpOverlapped );

int FlushFileBuffers( int hFile );
int DisconnectNamedPipe( int hNamedPipe );
int CloseHandle( int hObject );

// ----- Event 用
int CreateEventA(
int lpEventAttributes, // セキュリティ記述子
int bManualReset, // リセットのタイプ
int bInitialState, // 初期状態
char* lpName ); // イベントオブジェクトの名前

int OpenEventA(
int dwDesiredAccess, // アクセス権
int bInheritHandle, // 継承オプション
char* lpName ); // イベントオブジェクトの名前

int SetEvent( int hEvent );
int ResetEvent( int hEvent );

int WaitForSingleObject(
int hHandle, // オブジェクトのハンドル
int dwMilliseconds ); // タイムアウト時間:ミリ秒(ms)単位
]]
これで、本体プログラムはスッキリする?


それで、
1.クライアント側からサーバ側を起動する様にする
   クライアント:Master_Client.gsl
   サーバ:Slave_Server.gsl
2.PIPE は、これまで通りサーバ側で作成し、
  EVENT は、クライアント側で準備する。
   イベント(signal)の初期値は、off とする。
3.signal 状態:
   クライアント側から送ったら、off
   サーバ側から送り返したら、on
4.サンプルコード:
   クライアント側でキーボード入力し、
   サーバに送信し、
   サーバ側では、文字列を加工し、
   クライアント側に送り返す。
   キー入力が 'e' で処理終了。

結果のコード:

クライアント側コード:
------------- Master_Client.gsl
require'cdef_PIPE_Event_SUB'
print( 'Start' ) -- デバッグ用
----- 初期化1:イベント準備
-- イベントオブジェクト作成
EVN = C.CreateEventA( 0, 1, 0, charA('EVENT1') )
-- イベントオブジェクト取得
E1 = C.OpenEventA( 0x001F0003, 0, charA('EVENT1') )

----- 初期化2:サーバー立ち上げ
os.execute('start Slave_Server.gsl')
-- 立ち上げ確認:シグナル状態チェック for PIPE Open
repeat until band( C.WaitForSingleObject( E1, 1 ), 2 ) == 0 -- on 迄
----- PIPE オープン
P1 = C.CreateFileA(charA('\\\\.\\pipe\\PIPE1'), 3, 0, 0, 3, 0x80, 0 )
-- シグナル off に:初期化
C.ResetEvent( E1 )

-------------------- 主処理:(無限)ループ
while true do
print( 'Input: e for END' )
str = io.read() -- キー入力

-- シグナル off にして、リクエスト送信
C.ResetEvent( E1 )
rtn = C.WriteFile( P1, charA(str), #str, nIO, 0 ) --------------┐

if str == 'e' then break end

C.Sleep(100) ----- ダミー処理時間

-- シグナル状態チェック -- on 迄
repeat until band( C.WaitForSingleObject( E1, 1 ), 2 ) == 0
----- 結果受信
rtn=C.ReadFile( P1, charA(Buf), 4096, nIO, 0 ) --------------┘
str=ffi.string(Buf,nIO[0])
print( nIO[0], str )
end
C.CloseHandle( P1 )
print( 'End' ) -- デバッグ用
_=io.read(1)


サーバ側コード:
------------- Slave_Server.gsl
require'cdef_PIPE_Event_SUB'
print( 'Start Server' ) -- デバッグ用
----- マスタ(クライアント)から呼ばれた:
-- イベントオブジェクト取得
E1 = C.OpenEventA( 0x001F0003, 0, charA('EVENT1') )

-- パイプを作成
P1 = C.CreateNamedPipeA( charA("\\\\.\\pipe\\PIPE1"), 3, 0, 1, 0, 0, 100, 0 )
-- シグナル状態にする。
C.SetEvent( E1 )
-- Client オープン待ち
rtn=C.ConnectNamedPipe( P1, 0 )

----- 無限ループ:
while true do
-- シグナル状態チェック -- off 迄
repeat until band( C.WaitForSingleObject( E1, 1 ), 2 ) ~= 0
-- リクエスト受信
rtn=C.ReadFile( P1, charA(Buf), 4097, nIO, 0 ) -------------┐
if rtn==0 then break end
str=ffi.string(Buf,nIO[0])
print( nIO[0], str )
if str=='e' then break end

C.Sleep(500) ------ ダミー処理時間

-- シグナル on にして、結果送信
C.SetEvent( E1 )
rtn=C.WriteFile( P1, charA(str..'HOGE'), nIO[0]+4, nIO, 0 ) -------------┘
end
C.FlushFileBuffers( P1 )
C.DisconnectNamedPipe( P1 )
C.CloseHandle( P1 )
print( 'End Server' ) -- デバッグ用
_=io.read(1)

これで、
“Master_Client.gsl”をダブルクリックすると、・・・
出来ました。


ですが、
マスター(クライアント)も、スレーブ(サーバ)も、
送信する前に、イベント(シグナル)を設定している!

この件、
精神衛生上、逆にしたかったのだが、
何故だか、正常に動作しなかった???
仕方なく、送信直前に設定することにした。


本日はここまで。


“クライアント/サーバ”学習は続く。


見ていただいた序でとは厚かましい限りですが、
お帰りに投票して頂けるとなお嬉しいです。 ⇒ blogram投票ボタン


170112
関連記事
スポンサーサイト

コメントの投稿

管理者にだけ表示を許可する

おきてがみ/blogram
blogram投票ボタン



おきてがみ

最新記事
カレンダー
07 | 2017/08 | 09
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 - -
月別アーカイブ
カテゴリ
最新コメント
検索フォーム
リンク
プロフィール

<紙>

Author:<紙>
ようこそ。
「パソコンヲタクの雑記帳」
もろもろなことを綴っています。
パソコン ヲタクってねくら?
画像は kami でなく kani です。

カウンター(fc2、i2i) /Google Analytics


i2i(from 2010-08-24)
Total =
Today  =  
Yesterday=
アンチエイジング

Google Analytics
ブックマーク