「Raspbian「stretch」上にGO言語をインストール」でGo言語をインストールしましたが、今回はサーバアドレスを設定ファイルから読み込み、Json形式のデータをHTTPでサーバにアップロードします。アプリはWindows10上のVisual Studio Codeで開発し、Raspberry Pi上で動作させます。
開発環境
- Raspbian:buster
- go言語のバージョン:go1.13.4
- コーディング環境:Visual Studio Code 1.44.2
Go言語パッケージのインストール
次のコマンドで設定ファイルを読み込み用のパッケージ「ini.v1」をインストールします。
$ go get gopkg.in/ini.v1
パッケージ「ini.v1」
設定ファイルを読み込む機能を持つパッケージで、設定ファイルの形式を次に示します。詳細については「package ini」に示します。
config.ini
[web] url = https://tomosoft.jp/xxxxxx port = 443 [db] name = oreoredb user = userA
アプリの作成
作業フォルダ「gohttp」に次に示す「httpmain.go」「httplib.go」「inilib.go」を作成します。
- package名は「main」固定とします。これにより、別ファイルの変数も参照可能となります。最初の文字が大文字で始まる変数、関数等は、外部パッケージ(package名が異なる)から参照可能になります。
- package名「main」の関数名「main」がメインルーチンとなります。メインルーチンの前には初期化ルーチン「init」が最初に一度だけ実行されます。
- アプリは、メインルーチンからゴルーチン「send」を起動し、ゴルーチン「send」からチャンネル「httpch」を使用してJson形式の送信データをHTTPルーチンに通知します。
メインルーチン「main」と初期化ルーチン「init」を次に示します。
- 16行目で設定ファイルを読み込みます。
- 13行目でチャンネル「httpch」を作成し、20行目でゴルーチン「send」を起動し、26行目でチャンネル「httpch」から作成したJson形式の送信データをゴルーチン「send」に送信します。10秒ごとに送信データを更新して送信し続けます。
httpmain.go
package main import ( "fmt" "time" ) type Httpst struct { ID string data []byte } var httpch = make(chan Httpst) func init() { readconfig() } func main() { go send() var i byte = 1 for { b := []byte{0xff, uint8(i)} i++ httpch <- Httpst{"TomoSoft", b} time.Sleep(time.Second * 10) } fmt.Printf("Exit") }
HTTPルーチン「send」を次に示します。
- 20行目でチャンネル「httpch」を経由して送信するJson形式の送信データを受け取ります。
- 13行目いでJson形式「Sample 」を定義し、24行目でデータを作成します。
- 33行目でJson形式でサーバにデータを送信します。
httplib.go
package main import ( "bytes" "encoding/json" "fmt" "net/http" ) var URL string // sample structure type Sample struct { Id string `json: "id"` Count int `json: "Count"` } func httpsend() { URL = Cnf.Url senddata := <-httpch fmt.Printf("%#v\n", senddata) // build sample structure sample := new(Sample) sample.Id = senddata.ID sample.Count = int(senddata.data[1]) // encode json sample_json, _ := json.Marshal(sample) fmt.Printf("[+] %s\n", string(sample_json)) // send json res, err := http.Post(URL, "application/json", bytes.NewBuffer(sample_json)) defer res.Body.Close() if err != nil { fmt.Printf("[!] " + err.Error() + "\n") } else { fmt.Printf("[*] " + res.Status + "\n") } } func send() { for { httpsend() } }
設定ファイル読み込みルーチン「readconfig」を次に示します。
- 24行目のMustInt関数は、エラーが発生すると「0」を戻します。
- 25行目のMustString関数は、指定された文字列が空の場合、指定された文字列を戻します。
inilib.go
package main import ( "fmt" "gopkg.in/ini.v1" ) type Config struct { Url string Port int Db string User string } var Cnf Config func readconfig() { c, _ := ini.Load("conf/config.ini") // MustStringはデフォルトあり Stringはデフォルトなし、 Cnf = Config{ Url: c.Section("web").Key("url").String(), Port: c.Section("web").Key("port").MustInt(), Db: c.Section("db").Key("name").MustString("hogehoge.sql"), User: c.Section("db").Key("user").String(), } fmt.Printf("%v \n", Cnf.Url) fmt.Printf("%v \n", Cnf.Port) fmt.Printf("%v \n", Cnf.Db) fmt.Printf("%v \n", Cnf.User) }
アプリの実行
次のコマンドで作成したアプリをコンパイルして実行します。設定ファイルのデータが読み込まれ、指定したサーバアドレスにデータを送信されていることが確認できます。なお、あらかじめテスト用のサーバを起動しておき、サーバはデータを受信すると「200 OK」を戻します。
$ go build $ ./gohttp https://tomosoft.jp/xxxxx 443 oreoredb userA main.Httpst{ID:"TomoSoft", data:[]uint8{0xff, 0x1}} [+] {"Id":"TomoSoft","Count":1} [*] 200 OK main.Httpst{ID:"TomoSoft", data:[]uint8{0xff, 0x2}} [+] {"Id":"TomoSoft","Count":2} [*] 200 OK main.Httpst{ID:"TomoSoft", data:[]uint8{0xff, 0x3}} [+] {"Id":"TomoSoft","Count":3} [*] 200 OK main.Httpst{ID:"TomoSoft", data:[]uint8{0xff, 0x4}} [+] {"Id":"TomoSoft","Count":4} [*] 200 OK