SSブログ

Socket Debuggerを使ってみる! ポート:12!POSTの実装に向けて [NETWORK]

SocketDebugger
こことか、 https://www.udom.co.jp/sdg/
こことか、 http://sdg.ex-group.jp/lua.html
をまず見てね!

webServer_007.png内部処理を文字列で行うのか?テーブルで行うのか?どっちが得なんだよ!って事でテーブルで処理する事とします。
なんかあれですね、ファイル書き込みにappendモードが無いので受信データを一旦全部テーブルに保存している訳です。ファイル受信試験で数十kbyteのファイルはイイですが、ちょっと大きな、と言っても4Mbyte程度のjpgですがね、メモリが足りなくなってスクリプトの実行エラーが起きますね。
でも同じJPGファイルの送信時には発生しないのは謎ですね。


webServer_008.pngあとあれですね、全体的に転送が重いので、細かく多量の処理をするのではなく、こうまとまった受信データをいっきに処理したい場合は、内部プログラム受信バッファサイズを大きくとってしまいましょう!と言う話でやんす。



ソース全文
---------------------------------------------
-- 接続完了通知
---------------------------------------------
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

※、わたしあれ、正規表現さっぱりですわ!









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

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

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