Socket Debuggerを使ってみる! ポート:12!POSTの実装に向けて [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
内部処理を文字列で行うのか?テーブルで行うのか?どっちが得なんだよ!って事でテーブルで処理する事とします。
なんかあれですね、ファイル書き込みにappendモードが無いので受信データを一旦全部テーブルに保存している訳です。ファイル受信試験で数十kbyteのファイルはイイですが、ちょっと大きな、と言っても4Mbyte程度のjpgですがね、メモリが足りなくなってスクリプトの実行エラーが起きますね。
でも同じJPGファイルの送信時には発生しないのは謎ですね。
あとあれですね、全体的に転送が重いので、細かく多量の処理をするのではなく、こうまとまった受信データをいっきに処理したい場合は、内部プログラム受信バッファサイズを大きくとってしまいましょう!と言う話でやんす。
ソース全文
※、わたしあれ、正規表現さっぱりですわ!
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
内部処理を文字列で行うのか?テーブルで行うのか?どっちが得なんだよ!って事でテーブルで処理する事とします。
なんかあれですね、ファイル書き込みにappendモードが無いので受信データを一旦全部テーブルに保存している訳です。ファイル受信試験で数十kbyteのファイルはイイですが、ちょっと大きな、と言っても4Mbyte程度のjpgですがね、メモリが足りなくなってスクリプトの実行エラーが起きますね。
でも同じJPGファイルの送信時には発生しないのは謎ですね。
あとあれですね、全体的に転送が重いので、細かく多量の処理をするのではなく、こうまとまった受信データをいっきに処理したい場合は、内部プログラム受信バッファサイズを大きくとってしまいましょう!と言う話でやんす。
ソース全文
--------------------------------------------- -- 接続完了通知 --------------------------------------------- function OnConnected() Logput(1,'OnConnected') recvHttpTable = {} -- 受信データの一時格納用 recievedContentTable = {} -- HTTP文の内容格納用 recievedUrlStr = "" -- HTTP文のURL contentLength = 0 -- HTTP文の内容の取り込むべきサイズ operationCode = 0 -- 処理コード return 0 end --------------------------------------------- -- 送信ボタン押下 --------------------------------------------- function OnSendPush() Logput(1,'OnSendPush') a = GetEditorData() SendData(a) return 0 end --------------------------------------------- -- タイマー通知 --------------------------------------------- function OnTimer(id) Logput(1,'OnTimer') return 0 end --------------------------------------------- -- 受信通知 -- 0x0D is CR,0x0A is LF --------------------------------------------- function OnReceive(recv) Logput(1,'OnReceive') if operationCode == 0 then -- 初期状態? recvHttpTable = TableCat( recvHttpTable, recv ) -- 一時格納用テーブルに受信データを保存 if #recvHttpTable < 4 then return 0 end -- 配列の長さを確認 local head local body head,body = getHttpHeader( recvHttpTable ) -- 一時格納用テーブルからheaderとbodyに分ける if head ~= nil then -- headerに内容が入っている時 httpRequest( head, body ) -- HTTPリクエスト処理 if operationCode == 200 then -- 処理コード別の処理 Disconnect() elseif operationCode == 400 then Disconnect() elseif operationCode == 404 then Disconnect() elseif operationCode == 405 then Disconnect() else end else -- 受信はしたが、HTTP文の全てを受け取った訳ではない場合もある return 0 end elseif operationCode == 201 then recievedContentTable = TableCat( recievedContentTable, recv ) -- HTTP文の内容格納用テーブルに受信データを保存 if #recievedContentTable >= contentLength then -- 全て内容を受信できた場合 methodPost( recievedUrlStr, recievedContentTable ) -- method postの実行 Disconnect() end end return 0 end --------------------------------------------- -- 切断通知 --------------------------------------------- function OnDisConnected() Logput(1,'OnDisConnected') Disconnect() return 0 end --------------------------------------------- -- http request --------------------------------------------- function httpRequest( head, body ) local header = CharFromTbl( head ) -- 引数headの内容を文字列に変換 local headerLine = strSplit( header, "\r\n" ) -- 一行目を取得 local line1 = strSplit( headerLine[1], " " ) -- 一行目をスペースで区切る local methodStr = line1[1] -- 最初の単語 local urlStr = line1[2] -- 2番目の単語 local httpVersionStr = line1[3] -- 3番目の単語 recievedUrlStr = urlStr -- 大域変数にも保存 if strCmp( methodStr, 'GET' ) == 0 then -- GETの場合 local fileData = {} local mimeType = "" fileData, mimeType = methodGet( urlStr ) -- 構文解析して要求されたファイルデータとmime typeを返す if fileData ~= nil and mimeType ~= "" then index200( fileData, mimeType ) -- ファイル返信処理 operationCode = 200 -- 処理コード else index404() -- 該当ファイルが見つからない場合 operationCode = 404 -- 処理コード end elseif strCmp( methodStr, 'PUT' ) == 0 then -- PUTの場合 index405() -- 該当METHODが許されていない場合 operationCode = 405 -- 処理コード elseif strCmp( methodStr, 'POST' ) == 0 then -- POSTの場合 contentLength = 0 -- HTTP文の内容の取り込むべきサイズを一旦0にする for i = 1, #headerLine do -- headerの行数分ループ local compStr = "Content-Length:" -- 探したいのはContent-Length if strNCmp( headerLine[i], compStr, #compStr ) == 0 then -- 文字列の比較 local str = strSplit( headerLine[i], " " ) -- スペースで文字列を分割 contentLength = tonumber( str[2] ) -- 2番目の単語を数値に変換 break end end if contentLength > 0 then -- ヘッダーからContent-Lengthを取得できたなら if #body > 0 then -- 引き続きコンテンツが存在する? if #body >= contentLength then -- 全てのコンテンツを受信済み? methodPost( urlStr, body ) -- method postの実行 operationCode = 200 -- 処理コード else -- 全てのデータの受信が完了していないとき recievedContentTable = TableCat( recievedContentTable, body ) -- 受信コンテンツ格納用テーブルに追加保存 operationCode = 201 -- 処理コード end end else -- 構文解析失敗? operationCode = 200 -- 処理コード end elseif strCmp( methodStr, 'DELETE' ) == 0 then -- DELETEの場合 index405() -- 該当METHODが許されていない場合 operationCode = 405 -- 処理コード else index400() -- 不正なリクエスト operationCode = 400 -- 処理コード end end --------------------------------------------- -- method get --------------------------------------------- function methodGet( urlStr ) local file = {} local methodTbl = { { url = "/", path = "D:\\temp\\index.html", mime = "text/html" }, { url = "/index.html", path = "D:\\temp\\index.html", mime = "text/html" }, { url = "/index.htm", path = "D:\\temp\\index.html", mime = "text/html" }, { url = "/favicon.ico", path = "D:\\temp\\favicon.ico", mime = "image/png" }, { url = "/text.txt", path = "D:\\temp\\text.txt", mime = "text/plain" }, { url = "/photo1.jpg", path = "D:\\temp\\photo1.jpg", mime = "image/jpeg" }, { url = "/image1.png", path = "D:\\temp\\image1.png", mime = "image/png" }, { url = "/image2.bmp", path = "D:\\temp\\image2.bmp", mime = "image/bmp" }, { url = "/test.csv", path = "D:\\temp\\test.csv", mime = "text/csv" }, -- { url = "/test.bin", path = "D:\\temp\\test.bin", mime = "application/octet-stream" }, } for i = 1, #methodTbl do if strCmp( urlStr, methodTbl[i].url ) == 0 then file = FileRead( methodTbl[i].path ) return file, methodTbl[i].mime end end return nil,"" end --------------------------------------------- -- method post --------------------------------------------- function methodPost( urlStr, contents ) local path = "D:\\temp\\test" -- 保存先のフォルダーを指定 path = path .. strReplace( urlStr, "/", "\\" ) -- バックスラッシュを円マークに置換 Logput( 1, path ) FileWrite( contents, path ) -- テーブルの内容をファイルに書き込む end --------------------------------------------- -- http request status code = 200 --------------------------------------------- function index200( data, mimeType ) local contentLength = #data local contentHeader = 'HTTP/1.1 200 OK\r\n' .. 'Server: SocketeEbugger Web Server/ ver.0.1\r\n' .. 'Content-Type: ' .. mimeType .. ' charset=UTF-8\r\n' .. 'Content-Length: ' .. contentLength .. '\r\n' .. 'Connection: close\r\n\r\n' SendData( contentHeader ) SendData( data ) end --------------------------------------------- -- http request status code = 404 --------------------------------------------- function index404() local contentHeader = 'HTTP/1.0 404 Not Found\r\n' .. 'Connection: close\r\n\r\n' .. '<html><head><title>404 Not Found</title></head>\r\n' .. '<body>\r\n' .. '<h1>Not Found</h1>\r\n' .. '</body></html>\r\n' SendData( contentHeader ) end --------------------------------------------- -- http request status code = 400 --------------------------------------------- function index400() local contentHeader = 'HTTP/1.0 400 Bad Request\r\n' .. 'Connection: close\r\n\r\n' .. '<html><head><title>400 Bad Request</title></head>\r\n' .. '<body>\r\n' .. '<h1>Bad Request</h1>\r\n' .. '</body></html>\r\n' SendData( contentHeader ) end --------------------------------------------- -- http request status code = 405 --------------------------------------------- function index405() local contentHeader = 'HTTP/1.0 405 Method Not Allowed\r\n' .. 'Connection: close\r\n\r\n' .. '<html><head><title>405 Method Not Allowed</title></head>\r\n' .. '<body>\r\n' .. '<h1>Method Not Allowed</h1>\r\n' .. '</body></html>\r\n' SendData( contentHeader ) end --------------------------------------------- -- compare string A and string B. --------------------------------------------- function strCmp( stringA, stringB ) local strLen = string.len( stringA ) if strLen ~= string.len( stringB ) then return -1 end for i = 1, strLen do if string.byte( stringA, i ) ~= string.byte( stringB, i ) then return -1 end end return 0 end --------------------------------------------- -- compare string A and string B. --------------------------------------------- function strNCmp( stringA, stringB, n ) if n <= 0 then return -1 end for i = 1, n do if string.byte( stringA, i ) ~= string.byte( stringB, i ) then return -1 end end return 0 end --------------------------------------------- -- divide string by ts and enter table. -- https://qiita.com/peg/items/c472f7a7d9fcca1b5cb7 -- https://symfoware.blog.fc2.com/blog-entry-455.html --------------------------------------------- --[[ function strSplit(str, ts) -- 引数がないときは空tableを返す if ts == nil then return {} end local t = {} ; i=1 for s in string.gmatch(str, "([^"..ts.."]+)") do t[i] = s i = i + 1 end return t end ]] function strSplit( str, delim ) -- Eliminate bad cases... if string.find(str, delim) == nil then -- return { str } return nil end local result = {} local pat = "(.-)" .. delim .. "()" local lastPos for part, pos in string.gfind(str, pat) do table.insert(result, part) lastPos = pos end table.insert(result, string.sub(str, lastPos)) return result end --------------------------------------------- -- ASCIIテーブルをコード変換後に文字列化 -- -- ASCIIの例 -- 入力: { 0x30, 0x31, 0x32 } -- 返値: "012" -- http://amlaid.air-nifty.com/blog/2015/10/serial-debugger.html -- 0x0D is CR,0x0A is LF --------------------------------------------- function CharFromTbl(tbl) tblChar = {} for i=1, #tbl do if tbl[i] == 0x0D or tbl[i] == 0x0A then tblChar[i] = string.char(tbl[i]) else tblChar[i] = string.char(tbl[i]) end end return table.concat(tblChar) end --------------------------------------------- -- replace string to tr from ts and enter table. --------------------------------------------- function strReplace( str, before, after ) local str,num = string.gsub( str, before, after ) return str end --------------------------------------------- -- get http header from table -- CR is 0x0D LF is 0x0A --------------------------------------------- function getHttpHeader( tbl ) local header = {} local body = {} local tblLen = #tbl local index = 1 for i = 1, tblLen - 3 do if tbl[ i + 0 ] == 0x0D and tbl[ i + 1 ] == 0x0A and tbl[ i + 2 ] == 0x0D and tbl[ i + 3 ] == 0x0A then break else header[i] = tbl[i] index = index + 1 end end if index > tblLen - 3 then return nil,nil end for i = 1, tblLen do body[i] = tbl[ i + index + 3 ] end return header,body end
※、わたしあれ、正規表現さっぱりですわ!
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:11!Mime Typeの簡単な実装 [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
前回まででは、コンテンツはhtml文として決め打ちでしたが、今回はmime typeを指定していろいろなファイルの転送を可能とします。
これにより、ブラウザの左上にfaviconが表示されるようになったり、
CSVファイルのダウンロードなんかもできますね。
変更部分のみ
※ お役立ちリンク
https://asahi-net.jp/support/guide/homepage/0017.html
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
前回まででは、コンテンツはhtml文として決め打ちでしたが、今回はmime typeを指定していろいろなファイルの転送を可能とします。
これにより、ブラウザの左上にfaviconが表示されるようになったり、
CSVファイルのダウンロードなんかもできますね。
変更部分のみ
--------------------------------------------- -- http request --------------------------------------------- function httpRequest( request ) local len = #request if len < 4 then return 0 end local result = 0 if request[len - 3] == 0x0D and request[len - 2] == 0x0A and request[len - 1] == 0x0D and request[len - 0] == 0x0A then Logput( 1, 'end of the request message.' ) local reqStr = CharFromTbl( request ) local lineTbl = strSplit( reqStr, "\r\n" ) local line1Tbl = strSplit( lineTbl[1], " " ) local methodStr = line1Tbl[1] local urlStr = line1Tbl[2] local httpVersionStr = line1Tbl[3] if strCmp( methodStr, 'GET' ) == 0 then local fileData = {} local mimeType = "" fileData, mimeType = methodGet( urlStr, httpVersionStr ) if fileData ~= nil and mimeType ~= "" then index200( fileData, mimeType ) result = 200 else index404() result = 404 end elseif strCmp( methodStr, 'PUT' ) == 0 then index405() result = 405 elseif strCmp( methodStr, 'POST' ) == 0 then index405() result = 405 elseif strCmp( methodStr, 'DELETE' ) == 0 then index405() result = 405 else index400() result = 400 end end return result end --------------------------------------------- -- method get --------------------------------------------- function methodGet( urlStr, verStr ) local file = {} local methodTbl = { { url = "/", path = "D:\\temp\\index.html", mime = "text/html" }, { url = "/index.html", path = "D:\\temp\\index.html", mime = "text/html" }, { url = "/index.htm", path = "D:\\temp\\index.html", mime = "text/html" }, { url = "/favicon.ico", path = "D:\\temp\\favicon.ico", mime = "image/png" }, { url = "/text.txt", path = "D:\\temp\\text.txt", mime = "text/plain" }, { url = "/photo1.jpg", path = "D:\\temp\\photo1.jpg", mime = "image/jpeg" }, { url = "/image1.png", path = "D:\\temp\\image1.png", mime = "image/png" }, { url = "/image2.bmp", path = "D:\\temp\\image2.bmp", mime = "image/bmp" }, { url = "/test.csv", path = "D:\\temp\\test.csv", mime = "text/csv" }, -- { url = "/test.bin", path = "D:\\temp\\test.bin", mime = "application/octet-stream" }, } for i = 1, #methodTbl do if strCmp( urlStr, methodTbl[i].url ) == 0 then file = FileRead( methodTbl[i].path ) return file, methodTbl[i].mime end end return nil,"" end --------------------------------------------- -- http request status code = 200 --------------------------------------------- function index200( data, mimeType ) local contentLength = #data local contentHeader = 'HTTP/1.1 200 OK\r\n' .. 'Server: SocketeEbugger Web Server/ ver.0.1\r\n' .. 'Content-Type: ' .. mimeType .. ' charset=UTF-8\r\n' .. 'Content-Length: ' .. contentLength .. '\r\n' .. 'Connection: close\r\n\r\n' SendData( contentHeader ) SendData( data ) end
※ お役立ちリンク
https://asahi-net.jp/support/guide/homepage/0017.html
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:10!簡単なWeb Server [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
と言う訳で先人の知恵を借りて、文字列で処理をする事に。差分のみ
※ お役立ちリンク
https://qiita.com/peg/items/c472f7a7d9fcca1b5cb7
https://symfoware.blog.fc2.com/blog-entry-455.html
※ ともすれば変数がテーブルなのか?文字列なのか?それとも他の型なのか判らなくなってくるので、変数名、、、。
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
と言う訳で先人の知恵を借りて、文字列で処理をする事に。差分のみ
--------------------------------------------- -- http request --------------------------------------------- function httpRequest( request ) local len = #request if len < 4 then return 0 end local result = 0 if request[len - 3] == 0x0D and request[len - 2] == 0x0A and request[len - 1] == 0x0D and request[len - 0] == 0x0A then Logput( 1, 'end of the request message.' ) local reqStr = CharFromTbl( request ) local lineTbl = strSplit( reqStr, "\r\n" ) local line1Tbl = strSplit( lineTbl[1], " " ) local methodStr = line1Tbl[1] local urlStr = line1Tbl[2] local httpVersionStr = line1Tbl[3] if strCmp( methodStr, 'GET' ) == 0 then local fileData = methodGet( urlStr, httpVersionStr ) if fileData ~= nil then index200( fileData ) result = 200 else index404() result = 404 end elseif strCmp( methodStr, 'PUT' ) == 0 then index405() result = 405 elseif strCmp( methodStr, 'POST' ) == 0 then index405() result = 405 elseif strCmp( methodStr, 'DELETE' ) == 0 then index405() result = 405 else index400() result = 400 end end return result end --------------------------------------------- -- method get --------------------------------------------- function methodGet( urlStr, verStr ) local file = {} local methodTbl = { { url = "/", path = "D:\\temp\\index.html" }, { url = "/index.html", path = "D:\\temp\\index.html" }, { url = "/index.htm", path = "D:\\temp\\index.html" }, } for i = 1, #methodTbl do if strCmp( urlStr, methodTbl[i].url ) == 0 then file = FileRead( methodTbl[i].path ) return file end end return nil end --------------------------------------------- -- divide string by ts and enter table. -- https://qiita.com/peg/items/c472f7a7d9fcca1b5cb7 --------------------------------------------- function strSplit(str, ts) -- 引数がないときは空tableを返す if ts == nil then return {} end local t = {} ; i=1 for s in string.gmatch(str, "([^"..ts.."]+)") do t[i] = s i = i + 1 end return t end
※ お役立ちリンク
https://qiita.com/peg/items/c472f7a7d9fcca1b5cb7
https://symfoware.blog.fc2.com/blog-entry-455.html
※ ともすれば変数がテーブルなのか?文字列なのか?それとも他の型なのか判らなくなってくるので、変数名、、、。
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:9!簡単なWeb Server [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
前回のスクリプトがイマイチだったので、method GETのスクリプトをまず改造してみる。
今回はファイルパスを検索するのに連想配列を使う。ファイルの追加は容易になると思う。
※ もう少し上手く書ける気がする。修行が足らん、、、
※ お役立ちリンク
https://qiita.com/peg/items/c472f7a7d9fcca1b5cb7
https://symfoware.blog.fc2.com/blog-entry-455.html
※ 文字列で処理した方がお得なのか?、テーブルで処理した方がお得なのか?、、、悩みますな。
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
前回のスクリプトがイマイチだったので、method GETのスクリプトをまず改造してみる。
今回はファイルパスを検索するのに連想配列を使う。ファイルの追加は容易になると思う。
--------------------------------------------- -- method get --------------------------------------------- function methodGet( url, ver ) local file = {} local methodTbl = { { url = "/", path = "D:\\temp\\index.html" }, { url = "/index.html", path = "D:\\temp\\index.html" }, { url = "/index.htm", path = "D:\\temp\\index.html" }, } for i = 1, #methodTbl do local urlStr = CharFromTbl( url ) -- local verStr = CharFromTbl( ver ) if strCmp( urlStr, methodTbl[i].url ) == 0 then file = FileRead( methodTbl[i].path ) return file end end return nil end --------------------------------------------- -- compare string A and string B. --------------------------------------------- function strCmp( stringA, stringB ) local strLen = string.len( stringA ) if strLen ~= string.len( stringB ) then return -1 end for i = 1, strLen do if string.byte( stringA, i ) ~= string.byte( stringB, i ) then return -1 end end return 0 end
※ もう少し上手く書ける気がする。修行が足らん、、、
※ お役立ちリンク
https://qiita.com/peg/items/c472f7a7d9fcca1b5cb7
https://symfoware.blog.fc2.com/blog-entry-455.html
※ 文字列で処理した方がお得なのか?、テーブルで処理した方がお得なのか?、、、悩みますな。
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:8!簡単なWeb Server [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
なにか意味が有るのかと思わなくもないが、沈みかかった船なのでWeb Serverとか
Web ServerをSocket Debugger上に構築してブラウザからアクセスしてみた様子。内容はindex.htmlファイルとしてディスク上に保存、それを読み出す。
PCのブラウザとのやり取りの様子。
恒例のluaスクリプト
PCのコントロールキーのパッドの中にちっさなゴミが入ったのか、気になって仕方がない、、、
※もう少し上手く書ける気がする。修行が足らん、、、
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
なにか意味が有るのかと思わなくもないが、沈みかかった船なのでWeb Serverとか
Web ServerをSocket Debugger上に構築してブラウザからアクセスしてみた様子。内容はindex.htmlファイルとしてディスク上に保存、それを読み出す。
PCのブラウザとのやり取りの様子。
恒例のluaスクリプト
--------------------------------------------- -- 接続完了通知 --------------------------------------------- function OnConnected() Logput(1,'OnConnected') recvHttpTable = {} return 0 end --------------------------------------------- -- 送信ボタン押下 --------------------------------------------- function OnSendPush() Logput(1,'OnSendPush') a = GetEditorData() SendData(a) return 0 end --------------------------------------------- -- タイマー通知 --------------------------------------------- function OnTimer(id) Logput(1,'OnTimer') return 0 end --------------------------------------------- -- 受信通知 -- 0x0D is CR,0x0A is LF --------------------------------------------- function OnReceive(recv) Logput(1,'OnReceive') recvHttpTable = tableConcat( recvHttpTable, recv ) if #recvHttpTable < 4 then return 0 end result = httpRequest( recvHttpTable ) if result ~= 0 then --[[ if result == 200 then elseif result == 400 then elseif result == 404 then elseif result == 405 then else end ]] Disconnect() end return 0 end --------------------------------------------- -- 切断通知 --------------------------------------------- function OnDisConnected() Logput(1,'OnDisConnected') Disconnect() return 0 end --------------------------------------------- -- ASCIIテーブルをコード変換後に文字列化 -- -- ASCIIの例 -- 入力: { 0x30, 0x31, 0x32 } -- 返値: "012" -- http://amlaid.air-nifty.com/blog/2015/10/serial-debugger.html -- 0x0D is CR,0x0A is LF --------------------------------------------- function CharFromTbl(tbl) tblChar = {} for i=1, #tbl do if tbl[i] == 0x0D or tbl[i] == 0x0A then tblChar[i] = string.char(tbl[i]) else tblChar[i] = string.char(tbl[i]) end end return table.concat(tblChar) end --------------------------------------------- -- table concat --------------------------------------------- function tableConcat( tableA, tableB ) local tableALen = #tableA for i = 1, #tableB do tableA[ tableALen + i ] = tableB[i] end return tableA end --------------------------------------------- -- http request --------------------------------------------- function httpRequest( request ) local len = #request local result = 0 if request[len - 3] == 0x0D and request[len - 2] == 0x0A and request[len - 1] == 0x0D and request[len - 0] == 0x0A then Logput( 1, 'end of the request message.' ) local line1 = getLine( request ) local pos local method,url,httpVersion method,pos = split( line1, 0x20 ) -- 0x20 is ascii space line1 = tableCopyFrom( line1, pos + 1 ) url,pos = split( line1, 0x20 ) -- 0x20 is ascii space httpVersion,pos = tableCopyFrom( line1, pos + 1 ) local methodStr = CharFromTbl( method ) if string.match( methodStr, 'GET' ) ~= nil then local data = methodGet( url,httpVersion ) if data ~= nil then index200( data ) result = 200 else index404() result = 404 end elseif string.match( methodStr, 'PUT' ) ~= nil then index405() result = 405 elseif string.match( methodStr, 'POST' ) ~= nil then index405() result = 405 elseif string.match( methodStr, 'DELETE' ) ~= nil then index405() result = 405 else index400() result = 400 end end return result end --------------------------------------------- -- method get --------------------------------------------- function methodGet( url, ver ) local urlLen = #url local file = {} if urlLen == 1 then if url[1] == 0x2F then -- 0x2F is / file = FileRead( "D:\\temp\\index.html" ) else file = nil end else local urlStr = CharFromTbl( url ) if string.match( urlStr, '/index.html' ) ~= nil or string.match( urlStr, '/index.htm' ) ~= nil then file = FileRead( "D:\\temp\\index.html" ) else file = nil end end return file end --------------------------------------------- -- http request status code = 200 --------------------------------------------- function index200( data ) local contentLength = #data local contentHeader = 'HTTP/1.1 200 OK\r\n' .. 'Server: SocketeEbugger Web Server/ ver.0.1\r\n' .. 'Content-Type: text/html; charset=UTF-8\r\n' .. 'Content-Length: ' .. contentLength .. '\r\n' .. 'Connection: close\r\n\r\n' SendData( contentHeader ) SendData( data ) end --------------------------------------------- -- http request status code = 404 --------------------------------------------- function index404() local contentHeader = 'HTTP/1.0 404 Not Found\r\n' .. 'Connection: close\r\n\r\n' .. '<html><head><title>404 Not Found</title></head>\r\n' .. '<body>\r\n' .. '<h1>Not Found</h1>\r\n' .. '</body></html>\r\n' SendData( contentHeader ) end --------------------------------------------- -- http request status code = 400 --------------------------------------------- function index400() local contentHeader = 'HTTP/1.0 400 Bad Request\r\n' .. 'Connection: close\r\n\r\n' .. '<html><head><title>400 Bad Request</title></head>\r\n' .. '<body>\r\n' .. '<h1>Bad Request</h1>\r\n' .. '</body></html>\r\n' SendData( contentHeader ) end --------------------------------------------- -- http request status code = 405 --------------------------------------------- function index405() local contentHeader = 'HTTP/1.0 405 Method Not Allowed\r\n' .. 'Connection: close\r\n\r\n' .. '<html><head><title>405 Method Not Allowed</title></head>\r\n' .. '<body>\r\n' .. '<h1>Method Not Allowed</h1>\r\n' .. '</body></html>\r\n' SendData( contentHeader ) end --------------------------------------------- -- get line from string --------------------------------------------- function getLine( strTbl ) local line = {} -- search line position = getDelimiterPosition( strTbl, 0x0D ) -- 0x0D is CR if position == 0 then return nil end position = position + 1 for i = 1, position do line[i] = strTbl[i] end return line end --------------------------------------------- -- split table --------------------------------------------- function split( tbl, delimiter ) local index = 1 local copyTbl = {} for i = 1, #tbl do if tbl[i] == delimiter then break end index = index + 1 copyTbl[i] = tbl[i] end if index > #tbl then return nil,0 end return copyTbl,index end --------------------------------------------- -- get delimiter position --------------------------------------------- function getDelimiterPosition( tbl, delimiter ) local index = 1 for i = 1, #tbl do if tbl[i] == delimiter then break end index = index + 1 end if index > #tbl then return 0 end return index end --------------------------------------------- -- table copy from --------------------------------------------- function tableCopyFrom( tbl, pos ) local copyTbl = {} local index = 1 for i = pos, #tbl do copyTbl[ index ] = tbl[ i ] index = index + 1 end return copyTbl end
PCのコントロールキーのパッドの中にちっさなゴミが入ったのか、気になって仕方がない、、、
※もう少し上手く書ける気がする。修行が足らん、、、
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:7!簡単なWeb Cliente [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
気を取り直して、Web Clienteとして動作させてみます。HTTP文を色々考えるのは面倒なので、Arduino IDEのEtherntのWeb Clienteの例題を流用してみます。と言ってもスクリプトは非常に簡単ですがね。
取得したHTTP文はファイルに保存します。ではでは、設定から。
今回はポート1を使います。通信設定->接続:TCPクライアント動作とします。相手先アドレスが判らなくても右横の...ってボタンをクリックすればhost名で入力できますから。
通信設定->動作:スクリプトで動かします。
受信したデータをファイル化し、ブラウザで表示してみました。HTML文の前にHTTPの応答文が入っています。
Webサーバーとのやり取りです。Webサーバーはリクエストに答えると、基本切断して来ることが判ります。
今回作成したスクリプトです。作成したところのみを掲載しています。
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
気を取り直して、Web Clienteとして動作させてみます。HTTP文を色々考えるのは面倒なので、Arduino IDEのEtherntのWeb Clienteの例題を流用してみます。と言ってもスクリプトは非常に簡単ですがね。
取得したHTTP文はファイルに保存します。ではでは、設定から。
今回はポート1を使います。通信設定->接続:TCPクライアント動作とします。相手先アドレスが判らなくても右横の...ってボタンをクリックすればhost名で入力できますから。
通信設定->動作:スクリプトで動かします。
受信したデータをファイル化し、ブラウザで表示してみました。HTML文の前にHTTPの応答文が入っています。
Webサーバーとのやり取りです。Webサーバーはリクエストに答えると、基本切断して来ることが判ります。
今回作成したスクリプトです。作成したところのみを掲載しています。
--------------------------------------------- -- 送信ボタン押下 --------------------------------------------- function OnSendPush() Logput(1,'OnSendPush') local httpRequest = 'GET /search?q=arduino HTTP/1.1\r\n' .. 'Host: www.google.com\r\n' .. 'Connection: close\r\n\r\n' -- http request message. SendData( httpRequest ) -- send a request message to host. recvHtmlMsg = {} -- make a table for recieve message. return 0 end --------------------------------------------- -- 受信通知 --------------------------------------------- function OnReceive(recv) Logput(1,'OnReceive') recvHtmlMsg = tableConcat( recvHtmlMsg, recv ) -- append a message to variable return 0 end --------------------------------------------- -- 切断通知 --------------------------------------------- function OnDisConnected() Logput(1,'OnDisConnected') FileWrite( recvHtmlMsg, "D:\\temp\\receive.html" ) -- file write return 0 end --------------------------------------------- -- table concat --------------------------------------------- function tableConcat( tableA, tableB ) local tableALen = #tableA for i = 1, #tableB do tableA[ tableALen + i ] = tableB[i] end return tableA end
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:6! レコードを送りたい! [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
※SokcetDebuggerはビット演算を行う拡張関数が有りました!
通信で値を集めたレコードを送受信したい等という事はよくある要求じゃあないですか、特に業務辺りなら。
なのでレコード、C言語であれば構造体に値を代入してまるっと投げちゃうあれができるかどうかをやってみます。
送信処理のところを以下にしてみます。
つまり整数、実数、文字列がどうなるのか?
うーむ、最初の6個のデータはbyte型として送られ、浮動小数点型は0しか送られず、それ以降のデータは削除のようです。
LANアナライザー上でも7byteしか認められません。
さてさて、困ったねぇ、、、C言語の様に型が明確でないと変換どうするのかねぇ、、、
追記
結局のところこのSocket DebuggerでサポートしているLuaのver.5.1では数値は実数(double)であり、大きな数値ほど誤差が大きくなる。と言うか変数をネットワーク上に流すためにbyteデータに変換しようとしても正確に変換できない。
例えばある変数の値に-1を代入したとして、それが64bitの変数を期待している場合、ユーザーは16進数で
0xFFFFFFFFFFFFFFFF
を期待すると思うが、実際には誤差でオーバーフローして0x0000000000000000となってしまう、、、
さらにLuaのver.5.1ではビット演算子もシフト演算子もサポートしていないもの痛い。Luaのver.5.3では64bit整数もビット演算子もサポートされている様な気がする。
Luaのver.5.3リファレンスマニュアルより
こことか、 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 )
つまり整数、実数、文字列がどうなるのか?
うーむ、最初の6個のデータはbyte型として送られ、浮動小数点型は0しか送られず、それ以降のデータは削除のようです。
LANアナライザー上でも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のバージョンを上げて欲しい!
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
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 )
200ms周期くらいまでは比較的ちゃんと動いていたような気がしますが、100ms周期となると結構厳しい感じで、処理が遅れている様子が見て取れます。
例えばこの図では送信パケットのデータサイズが毎回1024byteであるのに対して受信パケットのサイズが1024以外の値を示す事が頻発します。また、停止ボタンなども効き辛くちょっと暴走気味です。
192.168.50.21が相手デバイスで、192.168.50.254がPCです。
LANアナライザーでは送受信ともに1024byteで行われています。これはSocketDebuggerか?、OSか?どちらかの内部処理の遅延が原因なのか、受信バッファの内容を複数パケット分処理している為に起きていると思われます。
まぁ何かしら限界も有るという事で、その辺も踏まえて使う必要が有るんじゃないかと。
※Windowを最小化して動かしている間は、タスクマネージャーのCPU負荷率はだいぶ減るので、可能ならばそれも有りなんではないかな。
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
前回ではタイマーを使って半自動化を行いましたが、今回はローカル(127.0.0.1)相手ではなく自作したネットワークデバイスを相手にして、タイマー周期を短くしてみました。
これですね!
SetTimer( 0, 100 )
200ms周期くらいまでは比較的ちゃんと動いていたような気がしますが、100ms周期となると結構厳しい感じで、処理が遅れている様子が見て取れます。
例えばこの図では送信パケットのデータサイズが毎回1024byteであるのに対して受信パケットのサイズが1024以外の値を示す事が頻発します。また、停止ボタンなども効き辛くちょっと暴走気味です。
192.168.50.21が相手デバイスで、192.168.50.254がPCです。
LANアナライザーでは送受信ともに1024byteで行われています。これはSocketDebuggerか?、OSか?どちらかの内部処理の遅延が原因なのか、受信バッファの内容を複数パケット分処理している為に起きていると思われます。
まぁ何かしら限界も有るという事で、その辺も踏まえて使う必要が有るんじゃないかと。
※Windowを最小化して動かしている間は、タスクマネージャーのCPU負荷率はだいぶ減るので、可能ならばそれも有りなんではないかな。
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:4! タイマーを使って自動化? [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
前回ではぽちぽちボタンを押すと言うアナログな送信でしたが、今回はタイマーを使って半自動化を行います。
まずfunction OnConnected()を以下の様に改造します。現在のタイマーの状態を保持する変数の生成と初期化です。
function OnSendPush()を以下の様に改造します。ここでは送信は行わず、タイマーの制御を行います。
function OnTimer(id)を以下の様に改造します。引数idはタイマーidが入っていますが、まあ今回はtimer1しか使っていませんので、、、
成功しているようです。
こことか、 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
成功しているようです。
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア:
Socket Debuggerを使ってみる! ポート:3! 送信データをスクリプトで生成 [NETWORK]
SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!
前回では送信データは送信データエディタ上のデータを使っていましたが、今回は自分でデータを作成して送信、受信、比較を行います。データはランダムな値です。
function OnSendPush()を以下の様に改造します。
成功しているようです。
こことか、 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
成功しているようです。
M5Stick ミニ開発キットESP32 1.3'OLEDオプションのブザーIRトランスミッタMpu9250
- 出版社/メーカー: M5Stack
- メディア: