SSブログ

Socket Debuggerを使ってみる! ポート:6! レコードを送りたい! [NETWORK]

SocketDebugger

こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html

をまず見てね!

※SokcetDebuggerはビット演算を行う拡張関数が有りました!


通信で値を集めたレコードを送受信したい等という事はよくある要求じゃあないですか、特に業務辺りなら。
なのでレコード、C言語であれば構造体に値を代入してまるっと投げちゃうあれができるかどうかをやってみます。
送信処理のところを以下にしてみます。
  -- レコードデータを生成する
  sendData = {0,1,2,3,4,5,0.12345,'designed by hamayan.'}
  SendData( sendData )

つまり整数、実数、文字列がどうなるのか?
record_transmit_013.pngうーむ、最初の6個のデータはbyte型として送られ、浮動小数点型は0しか送られず、それ以降のデータは削除のようです。


record_transmit_014.pngLANアナライザー上でも7byteしか認められません。


さてさて、困ったねぇ、、、C言語の様に型が明確でないと変換どうするのかねぇ、、、

追記
結局のところこのSocket DebuggerでサポートしているLuaのver.5.1では数値は実数(double)であり、大きな数値ほど誤差が大きくなる。と言うか変数をネットワーク上に流すためにbyteデータに変換しようとしても正確に変換できない。
例えばある変数の値に-1を代入したとして、それが64bitの変数を期待している場合、ユーザーは16進数で
0xFFFFFFFFFFFFFFFF
を期待すると思うが、実際には誤差でオーバーフローして0x0000000000000000となってしまう、、、
---------------------------------------------
-- convert int64 to byte array by big endian.
-- 数値は実数(double)型である為、例えば64bitで-1は正しく変換できない
---------------------------------------------
function ConvertInt64ToByteArrayBig( value )
--  value = value % 2 ^64

  local tbl = {}

  if value < 0 then 
    value = 2^64 + value 
  end

  tbl[ 1 ] = value / 2 ^ 56
  value = value % 2 ^ 56

  tbl[ 2 ] = value / 2 ^ 48
  value = value % 2 ^ 48

  tbl[ 3 ] = value / 2 ^ 40
  value = value % 2 ^ 40

  tbl[ 4 ] = value / 2 ^ 32
  value = value % 2 ^ 32

  tbl[ 5 ] = value / 2 ^ 24
  value = value % 2 ^ 24

  tbl[ 6 ] = value / 2 ^ 16
  value = value % 2 ^ 16

  tbl[ 7 ] = value / 2 ^ 8
  value = value % 2 ^ 8

  tbl[ 8 ] = value

  return tbl
end


さらにLuaのver.5.1ではビット演算子もシフト演算子もサポートしていないもの痛い。Luaのver.5.3では64bit整数もビット演算子もサポートされている様な気がする。

Luaのver.5.3リファレンスマニュアルより
「数値型には2種類の内部表現 (あるいは2つのサブタイプ) があります。 ひとつは整数で、もうひとつは浮動小数点数です。 それぞれの表現がいつ使われるかについては明確なルールがありますが、両者は必要に応じて自動的に変換されます (§3.4.3 を参照)。 そのためプログラマは整数と浮動小数点数の違いをほとんど無視することもできますし、各数値の表現について完全に制御を握ることもできます。 標準のLuaでは64ビットの整数と倍精度 (64ビット) の浮動小数点数を使用します」

「3.4.2 – ビット演算子
ビット演算子には以下のものがあります。

&: ビットごとの論理積
|: ビットごとの論理和
~: ビットごとの排他的論理和
>>: 右シフト
<<: 左シフト
~: 単項ビットごとの否定
ビット演算子はすべて、引数を整数に変換し (§3.4.3 を参照)、その整数の全ビットを演算し、結果を整数で返します。

右シフトと左シフトは両方とも、空いたビットをゼロで埋めます。 変位に負の値を指定すると逆方向にシフトします。 変位の絶対値が整数のビット数以上であれば結果はゼロになります (すべてのビットが追い出されます)。」
困ったねぇ、、、つまり正直言ってLuaのバージョンを上げて欲しい!

nice!(0)  コメント(0) 

Socket Debuggerを使ってみる! ポート:5! あまり受信頻度が高いと、、、 [NETWORK]

SocketDebugger

こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html

をまず見てね!

前回ではタイマーを使って半自動化を行いましたが、今回はローカル(127.0.0.1)相手ではなく自作したネットワークデバイスを相手にして、タイマー周期を短くしてみました。
これですね!
SetTimer( 0, 100 )

echo_actions_011.png200ms周期くらいまでは比較的ちゃんと動いていたような気がしますが、100ms周期となると結構厳しい感じで、処理が遅れている様子が見て取れます。
例えばこの図では送信パケットのデータサイズが毎回1024byteであるのに対して受信パケットのサイズが1024以外の値を示す事が頻発します。また、停止ボタンなども効き辛くちょっと暴走気味です。


echo_actions_012.png192.168.50.21が相手デバイスで、192.168.50.254がPCです。
LANアナライザーでは送受信ともに1024byteで行われています。これはSocketDebuggerか?、OSか?どちらかの内部処理の遅延が原因なのか、受信バッファの内容を複数パケット分処理している為に起きていると思われます。


まぁ何かしら限界も有るという事で、その辺も踏まえて使う必要が有るんじゃないかと。
※Windowを最小化して動かしている間は、タスクマネージャーのCPU負荷率はだいぶ減るので、可能ならばそれも有りなんではないかな。









nice!(0)  コメント(0) 

Socket Debuggerを使ってみる! ポート:4! タイマーを使って自動化? [NETWORK]

SocketDebugger

こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html

をまず見てね!

前回ではぽちぽちボタンを押すと言うアナログな送信でしたが、今回はタイマーを使って半自動化を行います。
まずfunction OnConnected()を以下の様に改造します。現在のタイマーの状態を保持する変数の生成と初期化です。
---------------------------------------------
-- 接続完了通知
---------------------------------------------
function OnConnected()
  Logput(1,'OnConnected')

  timer1StartIs = false  -- timer1の起動状態を記憶する変数を論理型で生成する

  return 0
end


function OnSendPush()を以下の様に改造します。ここでは送信は行わず、タイマーの制御を行います。
---------------------------------------------
-- 送信ボタン押下
---------------------------------------------
function OnSendPush()
  Logput(1,'OnSendPush')
--  sendData = GetEditorData()

  if timer1StartIs == true then
    timer1StartIs = false
    KillTimer( 0 )  -- timer1を停止する
  else
    timer1StartIs = true
    SetTimer( 0, 1000 )  -- timer1を1000ms周期で起動する
  end
  return 0
end


function OnTimer(id)を以下の様に改造します。引数idはタイマーidが入っていますが、まあ今回はtimer1しか使っていませんので、、、
---------------------------------------------
-- タイマー通知
---------------------------------------------
function OnTimer(id)
  Logput(1,'OnTimer')

  -- ランダムなデータを生成する
  sendData = {}  -- 空のテーブルを作成する
  for i = 1, 1024 do  -- 1024個のデータを生成
    sendData[ i ] = math.random( 255 )  -- 0から255までのランダムな整数を生成
  end
  SendData( sendData )

  return 0
end



echo_actions_010.png成功しているようです。










nice!(0)  コメント(0) 

Socket Debuggerを使ってみる! ポート:3! 送信データをスクリプトで生成 [NETWORK]

SocketDebugger

こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html

をまず見てね!

前回では送信データは送信データエディタ上のデータを使っていましたが、今回は自分でデータを作成して送信、受信、比較を行います。データはランダムな値です。
function OnSendPush()を以下の様に改造します。
---------------------------------------------
-- 送信ボタン押下
---------------------------------------------
function OnSendPush()
  Logput(1,'OnSendPush')

--  sendData = GetEditorData()

  -- ランダムなデータを生成する
  sendData = {}  -- 空のテーブルを作成する
  for i = 1, 1024 do  -- 1024個のデータを生成
    sendData[ i ] = math.random( 255 )  -- 0から255までのランダムな整数を生成
  end
  SendData( sendData )
  return 0
end



echo_actions_009.png成功しているようです。










nice!(0)  コメント(0) 

Socket Debuggerを使ってみる! ポート:2! 受信データをチェックしてみる [NETWORK]

SocketDebugger

こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html

をまず見てね!

前回ではエコーサーバーに対してユーザークライアントが適当なデータを投げて、サーバーから返ってきたデータを受信するまでをやりました、、、うーん受信したデータは大丈夫?って疑念が湧きますよね普通。

なので今回はスクリプトを自作して送信データと受信データの比較をしてみます。
以下の様なテーブル同士を比較するユーザー関数を作成してみました。ポート2のスクリプトファイルの一番最後にでも置いておきます。
---------------------------------------------
-- compare table A and table B.
---------------------------------------------
function compareTbl( tableA, tableB )
  local tableALen = #tableA  -- テーブルAの要素数を変数に代入
  local tableBLen = #tableB  -- テーブィBの要素数を変数に代入
  if tableALen ~= tableBLen then return -1 end  -- 要素数を比較して違うならエラーで帰る

  for i = 1, #tableA do  -- テーブル(配列)は1から始まり、要素数までループ
    if tableA[ i ] ~= tableB[ i ] then return -1  -- 要素同士を比較して違うならエラーで帰る
    end
  end

  return 0
end

微妙な違いですが送信ボタンのイベントの変数名を変えました。変数はlocal修飾子を付けないとグローバル変数扱いです。
---------------------------------------------
-- 送信ボタン押下
---------------------------------------------
function OnSendPush()
    Logput(1,'OnSendPush')
    sendData = GetEditorData()
    SendData( sendData )
    return 0
end

受信イベントを以下の様に変えました。
テーブル同士を比較してログ出力メッセージを変えています。
---------------------------------------------
-- 受信通知
---------------------------------------------
function OnReceive( recv )
  Logput( 1, 'OnReceive' )
  if compareTbl( sendData, recv ) == 0 then
    Logput( 1, 'Receive data was good.' )
  else
    Logput( 2, 'Receive data was not good.' )  -- 引数に2を指定すると注意、1なら情報、3なら警告
  end

  return 0
end


echo_actions_008.png成功しているようです。









nice!(0)  コメント(0) 

Socket Debuggerを使ってみる! ポート:1! [NETWORK]

SocketDebugger

こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html

をまず見てね!


ネットワークデバイスのデバックで最近利用を始めたSocketDebugger、無償版と有償版があります。
有償版に比較して無償版ではいくつかの機能が制限されますが、それでもとても有用なツールだと感じています。
特に、標準で備わっている機能だけでもデータの送受信を自動的に行うなどは容易に設定してできますが、Luaスクリプトを組むことでより詳細な動きを制御できます。

無償版は基本的な設定項目を保存することができませんが、Luaスクリプト自体はユーザーがエディタで作成し、保存、読み出しができますので、なるべくLuaスクリプトで処理をした方が同じようなデバックを何度も行うなら楽だと思います。


Lua?
ウイキペディア https://ja.wikipedia.org/wiki/Lua

参考にしているサイト
https://qiita.com/rohinomiya/items/abeb1d69c640a27d97c5

https://qiita.com/dwarfJP/items/e033728f5cbecbabe11f

http://amlaid.air-nifty.com/blog/2015/10/serial-debugger.html

https://qiita.com/satorimon/items/d65872659f7d6dc453fd

SocketDebuggerは2つのポート(ポート1とポート2)が同時に操作できますんで、わざわざターゲットを用意しなくてもSocketDebuggerだけでお試しやスクリプトの実行を行うことができます。

以下例ではポート1をTCPのエコーサーバー、ポート2をTCPのユーザークライアントだとします。
port1_connection_config_001.pngポート1の通信設定->接続の項目:TCPサーバー、IPアドレス127.0.0.1は自分自身を指定、ポート番号を1024で起動します。


port2_connection_config_002.pngポート2の通信設定->接続の項目:TCPクライアント、IPアドレス127.0.0.1は自分自身を指定、接続先ポート番号を1024で起動します。localポート番号を0にしておけば、適宜接続の度に適当なポート番号を割り当てるのでしょう。


port1_actions_config_003.pngポート1の通信設定->動作の項目:5000ms以内にデータの受信が無い時は切断します。また、受信時動作は受信データをそのまま返します。


port2_actions_config_004.pngポート2の通信設定->動作の項目:スクリプトで制御を行います。


スクリプト2のタブを開けばエディタが開き、スクリプトを編集できます。
標準の内容はそれぞれ発生したイベントに対する動作となっています。コメントはこちらで付けました。
---------------------------------------------
-- 接続完了通知
---------------------------------------------
function OnConnected()  -- 相手先と接続すると呼ばれるハンドラ
    Logput(1,'OnConnected')  -- 詳細ログデータ画面にメッセージを表示
    return 0
end
---------------------------------------------
-- 送信ボタン押下
---------------------------------------------
function OnSendPush()  -- 送信ボタンをクリックすると呼ばれるハンドラ
    Logput(1,'OnSendPush')
    a = GetEditorData()  -- 送信データエディタ上の内容を変数に代入
    SendData(a)  -- 変数の内容を送信
    return 0
end
---------------------------------------------
-- タイマー通知
---------------------------------------------
function OnTimer(id)  -- タイマーで設定した時間に呼ばれるハンドラ
    Logput(1,'OnTimer')
    return 0
end
---------------------------------------------
-- 受信通知
---------------------------------------------
function OnReceive(recv)  -- 相手から受信した時に呼ばれるハンドラ、引数のテーブル(recv)に受信データが格納されている
    Logput(1,'OnReceive')
    return 0
end
---------------------------------------------
-- 切断通知
---------------------------------------------
function OnDisConnected()  -- 切断された時に呼ばれるハンドラ
    Logput(1,'OnDisConnected')
    return 0
end

今回はポート2の送信ボタンが押された時の動作、function OnSendPush()を使う訳ですが、送信データエディタ上の内容をそのまま送信するならこのままで大丈夫です。
※送信データエディタ上に何もデータが無ければ、送信動作は行われません。

transmit_data_editor_005.pngエディタ上ではバイナリーデータですが、テキスト入力機能を使えばテキストを扱えます。


transmit_data_editor_006.png


これで準備が整いました。まずポート1のTCPサーバーを通信開始ボタンをクリックして起動します。画面にSocket処理開始と表示されている筈です。IDが1なのはポート1を示しています。

ポート2のユーザーTCPクライアントを通信開始ボタンをクリックして起動します。画面上にID:2のイベントが複数表示されます。何もしなければ5秒後に向こうから切断されてしまいます。

もう一度ポート2の通信開始ボタンで起動し、そのボタンの右隣のデータ送信ボタンをクリックしてみます。

echo_actions_007.png左上の画面で一連の送受信の様子や接続、切断処理が判ります。まずはこんな具合につこうてみて下さい。


echo_actions_008.png成功しているようです。









nice!(0)  コメント(0) 

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。