「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