以下、上記記事のコピペ
GitHub 上でサクッと空のディレクトリを作成する方法
golangによるudpの送信"だけ"するプログラムと受信だけするプログラム
// udp_sendto.go
// go run udp_sendto.go
// golangによるudpの送信"だけ"するプログラム
package main
import (
"fmt"
"math/rand"
"net"
"time"
)
func random(min, max float64) float64 {
return rand.Float64()*(max-min) + min
}
type unmTbl struct {
uniNum int
objType string // "Bus" or "User"
simNum int
pmNum int
lon float64
lat float64
}
func main() {
conn, err := net.Dial("udp4", "localhost:12345")
if err != nil {
panic(err)
}
defer conn.Close()
// 初期化
var ut [5]unmTbl
for i, _ := range ut {
ut[i].objType = "User"
ut[i].uniNum = i
ut[i].lat = 35.653976
ut[i].lon = 139.796821
}
for {
fmt.Println("Sending to server")
for i, _ := range ut {
ut[i].lat += random(0.5, -0.5) * 0.00001 * 10 * 5
ut[i].lon += random(0.5, -0.5) * 0.00002 * 10 * 5
str := ut[i].objType + "," + fmt.Sprint(ut[i].uniNum) + "," + fmt.Sprint(ut[i].lon) + "," + fmt.Sprint(ut[i].lat) + ","
fmt.Println(str)
_, err = conn.Write([]byte(str))
if err != nil {
panic(err)
}
time.Sleep(3 * time.Second) // 1秒休む
}
}
}
// udp_recvfrom.go
// go run udp_recvfrom.go
// golangによるudpの受信"だけ"するプログラム
package main
import (
"fmt"
"net"
)
func main() {
addr, _ := net.ResolveUDPAddr("udp", ":12345")
sock, _ := net.ListenUDP("udp", addr)
i := 0
for {
i++
buf := make([]byte, 1024)
rlen, _, err := sock.ReadFromUDP(buf)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(buf[0:rlen]))
//fmt.Println(i)
//go handlePacket(buf, rlen)
}
}
Golangの構造体やら動的リストやら
package main
import (
"fmt"
)
// 構造体の作り方
type unm_tbl struct {
obj_type string // "Bus" or "User"
sim_num int
pm_num int
}
func main() {
list := make([]unm_tbl, 0) // 構造体の動的リスト宣言
ut := unm_tbl{} // 構造体変数の初期化
ut.obj_type = "User"
ut.sim_num = 1
ut.pm_num = 0
list = append(list, ut) // 構造体をリストに動的追加
ut = unm_tbl{} // 構造体変数の初期化
ut.obj_type = "Bus"
ut.sim_num = 2
ut.pm_num = 1
list = append(list, ut) // 構造体をリストに動的追加
ut = unm_tbl{} // 構造体変数の初期化
ut.obj_type = "Taxi"
ut.sim_num = 3
//ut.pm_num = 3
list = append(list, ut) // 構造体をリストに動的追加
for i, _ := range list { // リスト分、ループする
fmt.Println(list[i].obj_type)
fmt.Println(list[i].sim_num)
fmt.Println(list[i].pm_num)
}
fmt.Println(list)
}
新しい言語の勉強って、たいてい、文字列処理で挫折するよね。
"You requested too many nodes (limit is 50000). Either request a smaller area, or use planet.osm" と言われた時の対応
https://www.openstreetmap.org/export#map=13/35.6367/139.8312 から、"You requested too many nodes (limit is 50000). Either request a smaller area, or use planet.osm"(ノード数が多すぎます(制限は50000)。もっと小さい領域を要求するか、 planet.osm を使用してください。) と言われた時の対応方法は以下の通りです。
(Step.1) 「ドラッグして別の領域を選択」を選択
(Step.2) 領域をマウスで拡大・変形した後、「Overpass API」を選択
(Step.3) 名前を付けて保存で、適当なファイル名(例 toyosu.osm)でセーブする
以上
Error response from daemon: open \\.\pipe\docker_engine_linux: The system cannot find the file specified. 等が出てきて、ドキっとする件
最近、PC起動時に、
C:\Users\ebata>docker ps
Error response from daemon: open \\.\pipe\docker_engine_linux: The system cannot find the file specified.
などが出てきて、ドキっとさせられる症状が頻発している。
基本的には、Dockerアイコンを使って再起動(Restart docker...)で、改善するんだけど、心臓に悪い。
近い内に、何か起こりそうな気がします。
Dockerの中にある、postgreSQLのpostGISのDB情報を、sqlファイルに変換する件
この環境↓を前提として、
Dockerの環境にて、ca_sim2ののダンプによるsqlファイル(map5.sql)の作成に先程成功しました。
[江端メモ]
root@6432e639f678:/db_data#
>pg_dump -U postgres ca_sim2 > map5.sql
>mv map5.sql /db_data (これ、カレントディレクトリで作業しているなら不要です)
C:\Users\ebata\toyosu>docker cp toyosu_db_1:/db_data/map5.sql map5.sql
(まあ、私の環境でなければ、分からないとは思います)
QGIS3でosmファイルを地図表示する方法
QGIS3でosmファイルを地図表示する方法
いつも、osmファイルをドラッグする場所を忘れるので、メモ
すると、こうなる。
以上
ゲストOSがLinuxのDockerコンテナの中から、ホストOSにデータを放り出す為に使ったUDPプログラム
0.追記(江端が、今、必要な情報をトップに)
### STLって面倒(strcpyでええやん)
// added by Ebata 2021/01/04
#include "simple_udp.h"
// Ebata added simple_udp 2021/01/05
simple_udp udp0("192.168.0.8",12345);
// added by Ebata 2021/01/04
std::cout << "Ebata:User: " << user.id() << "," << user.current_xy().x() << "," << user.current_xy().y() << std::endl;
std::stringstream ss;
ss << "Ebata:User: " << user.id() << "," << user.current_xy().x() << "," << user.current_xy().y() << std::endl;
// simple_udp udp0("192.168.0.8",12345);
udp0.udp_send("hello!\n");
//udp0.udp_send(ss); エラー
//udp0.udp_send(ss.c_str()); エラー
udp0.udp_send(ss.str());
1.背景
LinuxのDockerコンテナの中から、一方的に、ホストOSにデータを放り投げる為のUDPプログラムです。
1行程度のデータをコンテナの外に出したいだけなのに、なかなか、良い方法が見つからず、結局UDP socketを使ってしまいました(websocket用にサーバを作るのも大袈裟で面倒でした(3~4行程度で記述したかった))。
ちなみに、UDPは、相手がいようがいまいが、一方的に送信し、一方的に受信待ちができる、とても便利な通信方式です。当然、送達保証はありません。
2. 環境
私のホストOSのIPアドレスは、192.168.0.8、ポートは、12345 と適当に選びました。
普通DockerにはUDPのポートオープンの設定が必要だと思いますが、今回は、テストプログラムでたまたまpingとUDPが通ってしまったので、何もやっていません(運が良かっただけかもしれません)。
テスト用のUDPプログラムは、こちら「UDP送受信プログラム」を使いました(何でも残しておくものです)
3.ソースコード
まるまる、こちらをコピペさせて頂きました → 「メカトロ講座03 c++でudp通信をする方法」
一行でUDP送信ができるようにしたかったもので。
3.1 共通のヘッダファイル(simple_udp.h)
// g++ -std=c++11 としないと動かない(ことがある)
// simple_udp.h
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string> // "string.h"だと通らないことがあるので、注意のこと(私は、ここで2時間ほど嵌った)
class simple_udp{
int sock;
struct sockaddr_in addr;
public:
simple_udp(std::string address, int port){
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(address.c_str());
addr.sin_port = htons(port);
}
void udp_send(std::string word){
sendto(sock, word.c_str(), word.length(), 0, (struct sockaddr *)&addr, sizeof(addr));
}
void udp_bind(){
bind(sock, (const struct sockaddr *)&addr, sizeof(addr));
}
std::string udp_recv(){
#define BUFFER_MAX 400
char buf[BUFFER_MAX];
memset(buf, 0, sizeof(buf));
recv(sock, buf, sizeof(buf), 0);
return std::string(buf);
}
void udp_recv(char *buf, int size){
memset(buf, 0, size);
recv(sock, buf, size, 0);
}
~simple_udp(){
close(sock);
}
};
3.2 送信プログラム(udp_sendto.cpp)
// g++ udp_sendto.cpp -o udp_sendto で大丈夫だが、g++ -std=c++11としないと動かない(ことがある)
#include <stdio.h>
#include <string.h>
#include "simple_udp.h"
simple_udp udp0("192.168.0.8",12345); // ホストOSのUDPの受信側
int main(int argc, char **argv){
udp0.udp_send("hello!");
return 0;
}
3.3 受信プログラム(udp_recvfrom.cpp)
// g++ udp_recvfrom.cpp -o udp_recvfrom で大丈夫だが、g++ -std=c++11としないと動かない(ことがある)
#include <stdio.h>
#include <string.h>
#include "simple_udp.h"
simple_udp udp0("0.0.0.0",12345);
int main(int argc, char **argv){
udp0.udp_bind();
while (1){
std::string rdata=udp0.udp_recv();
printf("recv:%s\n", rdata.c_str());
}
return 0;
}
4.Windows10でMinGWのgccを使ってる私の場合のケース
以下のように変更した
4.1 共通のヘッダファイル(simple_udp_win.h)
// simple_udp_win.h
/* Windows版 */
#include <stdio.h>
#include <sys/types.h>
#include <winsock2.h>
#include <ws2tcpip.h>
//#include <sys/socket.h>
//#include <netinet/in.h>
//#include <arpa/inet.h>
//#include <netdb.h>
#include <string> // "string.h"だと通らないことがあるので、注意のこと(私は、ここで2時間ほど嵌った)
#include <unistd.h> // error: 'close' was not declared in this scope; did you mean 'fclose'?
class simple_udp{
int sock;
struct sockaddr_in addr;
// Windows専用おまじない(ここから)
WSADATA wsaData;
// Windows専用おまじない(ここまで)
public:
simple_udp(std::string address, int port){
// Windows専用おまじない(ここから)
WSAStartup(MAKEWORD(2,0), &wsaData);
// Windows専用おまじない(ここまで)
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(address.c_str());
addr.sin_port = htons(port);
}
void udp_send(std::string word){
sendto(sock, word.c_str(), word.length(), 0, (struct sockaddr *)&addr, sizeof(addr));
}
void udp_bind(){
bind(sock, (const struct sockaddr *)&addr, sizeof(addr));
}
std::string udp_recv(){
#define BUFFER_MAX 400
char buf[BUFFER_MAX];
memset(buf, 0, sizeof(buf));
recv(sock, buf, sizeof(buf), 0);
return std::string(buf);
}
void udp_recv(char *buf, int size){
memset(buf, 0, size);
recv(sock, buf, size, 0);
}
~simple_udp(){
close(sock);
}
};
4.2 送信プログラム(udp_sendto_win.cpp)
// g++ udp_sendto_win.cpp -o udp_sendto_win で大丈夫だが、g++ -std=c++11としないと動かない(ことがある)
// g++ -g udp_sendto_win.cpp -o udp_sendto_win -lwsock32 -lws2_32
#include <stdio.h>
#include <string.h>
//#include "simple_udp.h"
#include "simple_udp_win.h"
//simple_udp udp0("192.168.0.8",12345); // ホストOSのUDPの受信側
//simple_udp udp0("0.0.0.0",12345); // ホストOSのUDPの受信側
simple_udp udp0("127.0.0.1",12345); // ホストOSのUDPの受信側
int main(int argc, char **argv){
udp0.udp_send("hello!");
return 0;
}
4.3 受信プログラム(udp_recvfrom_win.cpp)
// g++ udp_recvfrom_win.cpp -o udp_recvfrom_win で大丈夫だが、g++ -std=c++11としないと動かない(ことがある)
// Windows の場合は、g++ -g udp_recvfrom_win.cpp -o udp_recvfrom_win -lwsock32 -lws2_32
#include <stdio.h>
#include <string.h>
#include "simple_udp.h"
//simple_udp udp0("0.0.0.0",12345); // ホストOSのUDPの受信側
simple_udp udp0("127.0.0.1",12345); int main(int argc, char **argv){ udp0.udp_bind(); while (1){ std::string rdata=udp0.udp_recv(); printf("recv:%s\n", rdata.c_str()); } return 0; }
「TILE38紹介」を紹介する
1.前書き
TILE38のクライアントプログラムのサンプルを見たくて、色々探していたら、「TILE38紹介」を紹介するという、非常に良いページを見つけました。
私がプログラムを良く忘れるので、このページのプログラムをそのままコピペさせて頂いて、私の備忘録とさせて頂きます(私の環境では、コメントアウト等がちょっと違ったようです)
2. 前提
Tile38のサーバを立ち上げておきます。Dockerを使って立ち上げておくと簡単です。dockerを使わない方法は、https://github.com/tidwall/tile38 に記載があります。
docker pull tile38/tile38
docker run -p 9851:9851 tile38/tile38
3. サンプルプログラム
(1つ目)
package main
import (
//"encoding/json"
"fmt"
"log"
//"reflect"
"github.com/garyburd/redigo/redis"
)
func main() {
// db connect
c, err := redis.Dial("tcp", ":9851")
if err != nil {
log.Fatalf("Could not connect: %v\n", err)
}
defer c.Close()
// SET location
ret, err := c.Do("SET", "location", "me", "POINT", 35.6581, 139.6975)
if err != nil {
log.Fatalf("Could not SET: %v\n", err)
}
fmt.Printf("SET ret:%s\n", ret)
// GET location
ret, err = c.Do("GET", "location", "me")
if err != nil {
log.Fatalf("Could not GET: %v\n", err)
}
fmt.Printf("GET ret:%s\n", ret)
}
(2つめ)
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/garyburd/redigo/redis"
)
type GeoJsonMember struct {
Type string `json:"type"`
CoordinatesRaw json.RawMessage `json:"coordinates,omitempty"`
CoordinatesObj interface{} `json:"-"`
}
type Point [2]float64
type LineString []Point
type Polygon []LineString
func (member *GeoJsonMember) String() string {
return fmt.Sprintf("%s %v", member.Type, member.CoordinatesObj)
}
func (member *GeoJsonMember) setCoordinates() error {
var coordinates interface{}
switch member.Type {
case "Point":
coordinates = new(Point)
case "LineString":
coordinates = new(LineString)
case "Polygon":
coordinates = new(Polygon)
default:
return fmt.Errorf("Unknown type: %v", member.Type)
}
err := json.Unmarshal(member.CoordinatesRaw, &coordinates)
if err != nil {
return fmt.Errorf("json.Unmarshal error: %v", err)
}
member.CoordinatesObj = coordinates
return nil
}
func unmarshalMultiResults(shapes []byte) ([]*GeoJsonMember, error) {
var members []*GeoJsonMember
err := json.Unmarshal(shapes, &members)
if err != nil {
return nil, fmt.Errorf("Unmarshal error: %v", err)
}
for i, member := range members {
err := member.setCoordinates()
if err != nil {
return nil, fmt.Errorf("member[%v]:type:%v coordinates:%v err:%v\n", i, member.Type, member.CoordinatesRaw, err)
}
}
return members, nil
}
func unmarshalSingleResult(shapes []byte) (*GeoJsonMember, error) {
var member GeoJsonMember
err := json.Unmarshal(shapes, &member)
if err != nil {
return nil, fmt.Errorf("Unmarshal error: %v", err)
}
err = member.setCoordinates()
if err != nil {
return nil, fmt.Errorf("type:%v coordinates:%v err:%v\n", member.Type, member.CoordinatesRaw, err)
}
return &member, nil
}
func main() {
// db connect
c, err := redis.Dial("tcp", ":9851")
if err != nil {
log.Fatalf("Could not connect: %v\n", err)
}
defer c.Close()
// SET fleet
for _, data := range [][]interface{}{
{"fleet", "id1", "FIELD", "start", "123456", "FIELD", "end", "789012", "POINT", 35.6581, 139.6975},
{"fleet", "id2", "OBJECT", `{"type":"Point","coordinates":[139.6975,35.6581]}`},
{"fleet", "id3", "OBJECT", `{"type":"LineString","coordinates":[[139.6975,35.6581],[1,1],[2,2]]}`},
{"fleet", "id4", "POINT", 35.6581, 139.6975},
} {
ret, err := c.Do("SET", data...)
if err != nil {
log.Fatalf("Could not SET: %v\n", err)
}
fmt.Printf("SET ret:%#s\n", ret)
}
// SCAN fleet
results, err := redis.Values(c.Do("SCAN", "fleet"))
if err != nil {
log.Fatalf("Could not SCAN: %v\n", err)
}
var cursor int
var members []interface{}
_, err = redis.Scan(results, &cursor, &members)
if err != nil {
fmt.Printf("scan result error: %v", err)
return
}
for len(members) > 0 {
// pick up one record from results as []interface{}
var object []interface{}
members, err = redis.Scan(members, &object)
if err != nil {
fmt.Printf("scan record error: %v", err)
return
}
// scan columns from one record -> [id,json],fields
var id []byte
var json []byte
others, err := redis.Scan(object, &id, &json)
if err != nil {
fmt.Printf("scan columns error: %v", err)
return
}
// unmarshal geojson string to struct
gjm, err := unmarshalSingleResult(json)
if err != nil {
fmt.Printf("unmarshal json error: %v", err)
return
}
fmt.Printf("id:%s json:%s others:%s\n", id, gjm, others)
}
}
4. PruneMobileと組み合わせてみる
ランダムウォークさせている歩行者が、一定のエリアに入った時に、メッセージを送付する。
XXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXX
cgoの使い方メモ(不定期に更新)
- 参考文献
https://r9y9.github.io/blog/2014/03/22/cgo-tips/
https://hawksnowlog.blogspot.com/2018/12/getting-started-with-cgo.html - 取り敢えず、Goのプログラムの中からCの関数を使う方法
// go run main.go package main /* #include <stdio.h> #include <stdlib.h> void myprint(char* s) { printf("%s\n", s); } */ import "C" import "unsafe" func main() { cs := C.CString("Hello from stdio\n") C.myprint(cs) C.free(unsafe.Pointer(cs)) } // output // Hello from stdio
とか
package main /* #include <math.h> double MyPow(double x, double y) { double ret = pow(x, y); return ret; } */ import "C" import "fmt" func main() { ret := C.MyPow(10, 2) fmt.Println(ret) }
- 結構面倒くさい決まりごと
(1)import "C" の前には空行を入れない// #include <stdio.h> // #include <errno.h> import "C"
(2)C / C++ のコンパイラに渡すオプション(flag)を記述する
// #cgo CFLAGS: -I/usr/local/lib import C