20170104 go publish...22 hello world package main import "fmt" func main() {...

202
GO言語でWEBサーバを作れるか!? どのレベルで作るの?

Upload: others

Post on 14-Jul-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

GO言語でWEBサーバを作れるか!?どのレベルで作るの?

Page 2: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

2

自己紹介

岩松竜也いわまつ たつや

株式会社ビズリーチ HRMOS事業部 採用管理チーム Scalaエンジニア 2015年4月 新卒入社

最近はZ戦士などと認知されています🙄https://speakerdeck.com/iwamatsu0430/scalazdeuebuapurimocha-la-head-cha-la

Page 3: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

3

目的

Go言語を1から学ぶ

インターネットの仕組みを学ぶ

Go言語を使ってWebサーバを作ってみる

Page 4: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

4

時間割

第一部 Go Introduction 13:00 ~ 14:20

休憩 14:20 ~ 14:30

第二部 WEBサーバを作ろう! 14:30 ~ 16:50

休憩 16:50 ~ 17:00

第三部 低層に触れてみよう! 17:00 ~ 18:00

Page 5: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部 Golang Introduction

Page 6: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

Go言語とは

Page 7: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

7

Go言語とは

developed by

Page 8: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

8

Go言語とは主な設計者

Rob Pike Ken Thompson

UNIX、Plan9、UTF-8、 世界初のUNIX用ウィンドウシステム の開発など

左の人(右の人はDennis Ritchie) B言語、C言語、UNIXのオリジナル開発者 正規表現、UTF-8など

レジェンドすぎ…😱

Page 9: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

9

Go言語とは簡潔

不思議な文法が少ない(暗黙的な型変換とか)

使われていない変数やパッケージにうるさい

セミコロン不要、型推論ありと近代的

Page 10: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

10

Go言語とは様々な動作環境

Mac, Linux, Windows, Android, iOS

実行バイナリへクロスコンパイル可能

Goソースコード

コンパイル

Page 11: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

11

Go言語とは様々な動作環境

Mac, Linux, Windows, Android, iOS

実行バイナリへクロスコンパイル可能

Goソースコード

コンパイル

一つの環境だけでOK 例えばMacだけで

Windwosバイナリ(exe)が作成可能

すぐ使える! JVMや.NET、Ruby等のように

実行用の設定が不要!

Page 12: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

12

Go言語とは高速・高機能

コンパイル、実行が超早い

標準ライブラリがとても充実

Cっぽいけど並列処理機能、GCが標準で用意

Page 13: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

環境セットアップ

Page 14: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

14

環境セットアップ

http://golang-jp.org/

Page 15: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

15

環境セットアップ$ brew install go

$ vim ~/.bach_profile

# 設定例 (wgetの場合は配置先を指定すること) PATH=$PATH:/Users/{ユーザ名}/bin/go/1.7.4/bin # brewの場合は不要 export GOPATH=/Users/{ユーザ名}/.go # 適当な場所 export GOROOT=/Users/{ユーザ名}/bin/go/1.7.4 # brewの場合は不要

$ wget https://storage.googleapis.com/golang/go1.7.4.darwin-amd64.tar.gz

OR

AND THEN

Page 16: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

16

環境セットアップ

$ git clone https://github.com/iwamatsu0430/goeasy.git $ ./go run main.go

docker環境もあります😎

Page 17: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

Hello World

Page 18: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

18

Hello World

package main

import "fmt"

func main() { fmt.Println(“Hello, World!”) }

$ go run main.go

Page 19: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

19

Hello World

package main

import "fmt"

func main() { fmt.Println(“Hello, World!”) }

$ go run main.go

パッケージ指定 Java, Scala等と同じ

Page 20: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

20

Hello World

package main

import "fmt"

func main() { fmt.Println(“Hello, World!”) }

$ go run main.go

import文 他のパッケージを使えるように

Page 21: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

21

Hello World

package main

import "fmt"

func main() { fmt.Println(“Hello, World!”) }

$ go run main.go

main関数 プログラムの最初に呼ばれる

Page 22: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

22

Hello World

package main

import "fmt"

func main() { fmt.Println(“Hello, World!”) }

$ go run main.go

Println関数 console.log, printlnと同じ

Page 23: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

基本的な機能紹介

Page 24: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

24

基本的な機能紹介

https://play.golang.org/

$ go run main.go

書いてみよう!

OR

Page 25: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

25

変数

package main

import "fmt"

func main() { var foo int foo = 123 fmt.Println(foo) }

変数宣言 var {変数名} {型}

Page 26: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

26

変数Go言語の基本型

数値int float など

文字列 string

真理値 bool

配列[]int

[]string など

Page 27: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

27

変数値がないと…

初期値が入ってる(intの場合0)

Page 28: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

28

変数未使用の変数がいると

「使ってないぞ😡」と怒られる

Page 29: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

29

変数

package main

import "fmt"

func main() { var foo = 123

bar := 123 fmt.Println(foo) fmt.Println(bar) }

Page 30: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

30

変数

package main

import "fmt"

func main() { var foo = 123

bar := 123 fmt.Println(foo) fmt.Println(bar) }

型指定は省略可能 暗黙的に変換してくれる

Page 31: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

31

変数

package main

import "fmt"

func main() { var foo = 123

bar := 123 fmt.Println(foo) fmt.Println(bar) }

varも省略可能 変数名 := 値

Page 32: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

32

配列

package main

import "fmt"

func main() { arr := []int{1,2,3} arr = append(arr, 4) fmt.Println(arr) }

配列初期化 []型名{初期値, 初期値,,,}

[]型名 => 型名

要素の追加 非破壊的な操作になるので

arrを上書きしてあげる必要あり

Page 33: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

33

配列

arr := []int{1,2,3}

// 要素数の取得 len(arr)

// 範囲で取得 arr[1:3] // 1番目から3番目の要素を取得 arr[1:] // 1番目以降の要素を取得

// 配列同士の結合 append(arr, arr...)

基本的な使い方

詳しくは逆引きGolang (配列)でhttp://ashitani.jp/golangtips/tips_slice.html

Page 34: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

34

Map

package main

import "fmt"

func main() { m := map[string]int{"pen":100,"pineapple":200} fmt.Println(m) m["apple"] = 300 m["pen"] = 400 fmt.Println(m) }

mutableな挙動 存在しなければ追加 存在すれば更新

詳しくは逆引きGolang (Map)でhttp://ashitani.jp/golangtips/tips_map.html

Page 35: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

35

制御構文if

package main

import "fmt"

func main() { if 1 > 0 { fmt.Println("1は0より大きい!") } else if 1 == 0 { fmt.Println("1は0と同じ!") } else { fmt.Println("1は0より小さい!") } }

丸括弧()は不要 複雑な条件では付けても良い

else if スペースが必要

Page 36: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

36

制御構文if(複数の式)

package main

import "fmt"

func main() { if x := 1; x > 0 { fmt.Println("x > 0") } else { fmt.Println("x <= 0") } // fmt.Println(x) }

;で区切れる 初期化などをここでできる

最後の式が評価 boolを返す必要あり

ローカル変数 xはif内でしか扱えない

Page 37: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

37

制御構文for(基本)

package main

import "fmt"

func main() { for i := 0; i < 10; i++ { fmt.Println(i) } }

Page 38: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

38

制御構文for(while的)

package main

import "fmt"

func main() { i := 0 for i < 10 { fmt.Println(i) i++ } }

条件のみ go言語にwhileはない

Page 39: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

39

制御構文for(foreach的)

package main

import "fmt"

func main() { arr := []int{1,2,3} for i := range arr { fmt.Println(arr[i]) } }

range 位置 := range 配列

Page 40: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

40

制御構文for(foreach的2)

package main

import "fmt"

func main() { arr := []int{1,2,3} for i, num := range arr { fmt.Println(arr[i]) fmt.Println(num) } }

値も直接取れる 位置, 値 := range 配列

Page 41: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

41

制御構文

package main

import "fmt"

func main() { i := 0 for { fmt.Println(i) i++ if i >= 10 { break } } }

条件なしで無限 扱いには注意!

for(無限ループ)

break ブロックを抜ける時に使用

Page 42: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

42

制御構文

package main

import "fmt"

func main() { i := 3 switch i { case 0: fmt.Println("i = 0") case 1: fmt.Println("i = 1") default: fmt.Println("unknown") } }

switch(基本)

breakは不要 fall throughではない

Page 43: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

43

制御構文

package main

import "fmt"

func main() { i := 3 switch i { case 0: fmt.Println("i = 0") // case "1": fmt.Println("i = 1") default: fmt.Println("unknown") } }

switch(型チェック)

入力との型を確認 違う型が入ってくると コンパイルエラーになる

Page 44: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

44

制御構文

package main

import "fmt"

func main() { i := 1 switch i { case 0,1: fmt.Println("i = 0 or 1") case 2: fmt.Println("i = 2") default: fmt.Println("unknown") } }

switch(複数の条件)

,で複数の条件 処理をまとめたいときなど

Page 45: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

45

制御構文

package main

import "fmt"

func main() { i := 3 switch { case i % 2 == 0: fmt.Println("偶数") case i < 0: fmt.Println("負数") default: fmt.Println("unknown") } }

switch(if-else)

入力を置かない caseに条件を設定する

Page 46: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

46

制御構文

package main

import "fmt"

func main() { i := 4 switch { case i % 2 == 0: { fmt.Println("偶数") fmt.Println("😂 ") } default: fmt.Println("unknown") } }

switch(複数の処理)

{}で書ける 関数の呼び出しでも良い

Page 47: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

47

関数

package main

import "fmt"

func Foo() { fmt.Println("foo") }

func main() { Foo() Bar("bar!") }

func Bar(msg string) { fmt.Println(msg) }

関数の定義 func 関数名() {}

呼び出し 同じパッケージ内ならそのまま使用

引数の設定 他の言語と同じ

Page 48: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

48

関数

package main

import "fmt"

func sum(n int, m int) int { return n + m }

func main() { fmt.Println(sum(1,2)) }

返り値あり関数

返り値の定義 func 関数名() 返り値の型 {}

return 返り値を渡す

Page 49: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

49

関数

package main

import "fmt"

func sum(n int, m int) (l int) { l = n + m return }

func main() { fmt.Println(sum(1,2)) }

返り値あり関数

返り値用変数 func 関数名() (変数名 返り値の型) {}

return returnのみでよい

Page 50: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

50

関数

package main

import "fmt"

func tuple() (int, string) { return 1, "a" }

func main() { num, str := tuple() fmt.Println(num) fmt.Println(str) }

タプル

2つの返り値 変数初期化もできる

Page 51: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

51

関数

package main

import "fmt"

func tuple() (int, string) { return 1, "a" }

func main() { num, _ := tuple() fmt.Println(num) }

タプル

_で省略 値を使わない場合は

_でも大丈夫

Page 52: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

52

関数

// 関数オブジェクト foo := func(msg string) { fmt.Println(msg) } foo("hello!")

// 関数を引数に取る関数 bar := func(f func(string)) { f("world!") } bar(foo)

関数いろいろ

Page 53: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

53

関数

// 関数を引数に取って関数を返す関数 baz := func(f func(string)) func(string, int) { return func(msg string, n int) { for n > 0 { f(msg) n-- } } } baz(foo)("aaa", 3)

関数いろいろ

おっ関数型かな…?

Page 54: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

54

構造体

package main

import "fmt"

type foo struct { Bar int Baz string }

func main() { f := foo{} fmt.Println(f.Bar) f.Baz = "foobarbaz" fmt.Println(f.Baz) }

型の定義 type 型名 struct {}

フィールド定義 大文字: Public

小文字: Private(パッケージ内のみ)

型の初期化 foo型になっている

Page 55: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

55

構造体

// 初期値の設定も一緒に可能 f1 := foo{123, "foo"} fmt.Println(f1)

// フィールド名指定の初期化 f2 := foo{Baz: "foo", Bar: 123} fmt.Println(f2)

// 配列にもできる farr := []foo{f1, f2} fmt.Println(farr)

構造体いろいろ

Page 56: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

56

構造体

func (f foo) Qux() { fmt.Println(f.Baz) }

func main() { f := foo{123, "foo"} f.Qux() }

関数を持たせる

構造体の関数定義 func (変数名 型名) 関数名

Page 57: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

57

構造体

type qux struct { foo }

func (f foo) Corge() { fmt.Println(f.Baz) }

func main() { q := qux{} q.Baz = "world" q.Corge() }

埋め込み(embed)

継承 埋め込み 型名をそのまま指定

Page 58: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

58

interface

package main

import "fmt"

type foo struct {} type bar struct {}

type baz interface { Qux() }

interface宣言 type 型名 interface {}

持たせたいフィールドを指定

Page 59: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

59

interface

func (f foo) Qux() { fmt.Println("foo!") }

func (b bar) Qux() { fmt.Println("bar!") }

func main() { Corge(foo{}) Corge(bar{}) }

func Corge(b baz) { b.Qux() }

フィールドを実装 それぞれ実装すれば

同じinterfaceとみなせる

引数をinterfaceに 同じフィールドを持っていればOK

ダックタイピング的

Page 60: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

60

interface

package main

import "fmt"

func main() { f := func(x interface{}) { fmt.Println(x) } f(1) f("hoge") }

ちなみに

Any的な使い方も! 空のinterface{}を指定する

Page 61: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

var x int = 1 var y *int = &x fmt.Println(x) // ① fmt.Println(y) // ② fmt.Println(*y) // ③

61

ポインタ

yはxのポインタ メモリのアドレスを示している

Page 62: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

62

ポインタ

一個のマスごとにデータが入っている

メモリのイメージ

0x00000001 0x00000010 0x00000011

それぞれアドレスが割り振られている

Page 63: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

63

ポインタ

変数x

メモリ

①の場合

値が格納される xはアドレスを記憶

1

Page 64: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

1

64

ポインタ

変数x

メモリ

①の場合

値を取得 xの値をください

fmt.Println(x)

Page 65: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

65

ポインタ

変数x

メモリ

①の場合

アドレスを参照 ここにあるで

1

fmt.Println(x)

Page 66: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

66

ポインタ

変数x

メモリ

①の場合

1

fmt.Println(x)

変数xの値を取得 x = 1

Page 67: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

67

ポインタ

メモリ

②の場合

1

値が格納される xはアドレスを記憶

変数x 変数y

Page 68: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

68

ポインタ

メモリ

②の場合

1

変数x 変数y

アドレスのみ取得 y := &x

&をつけるとアドレスの取得となる

Page 69: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

69

ポインタ

メモリ

②の場合

1

変数x 変数yfmt.Println(y)

yの値を取得 値をください

Page 70: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

70

ポインタ

メモリ

②の場合

1

変数x 変数yfmt.Println(y)

xのアドレスを返す 持ってるのはこれだけやで

変数yの値を取得 y = 0x1040e0f8

Page 71: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

71

ポインタ

メモリ

③の場合

1

変数x 変数yfmt.Println(*y)

実体をください アドレスの先にある値を取得

Page 72: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

72

ポインタ

メモリ

③の場合

1

変数x 変数yfmt.Println(*y)

値を参照 ここやで

Page 73: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

73

ポインタ

メモリ

③の場合

1

変数x 変数yfmt.Println(*y)

変数yの実体を参照 y = 1

Page 74: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

74

ポインタ何が嬉しいの?

メモリを効率的に使える

Page 75: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

75

ポインタ何が嬉しいの?

Page 76: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

76

ポインタ何が嬉しいの?

アドレスが違う! 値だけコピーされる

Page 77: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

77

ポインタ何が嬉しいの?

Page 78: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

78

ポインタ何が嬉しいの?

アドレスが違う! 値だけコピーされる

Page 79: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

79

ポインタ何が嬉しいの?

Page 80: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

80

ポインタ何が嬉しいの?

アドレスが違う! 同じ値なのに

メモリがちょっともったいない…

Page 81: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

81

ポインタ何が嬉しいの?

Page 82: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

82

ポインタ何が嬉しいの?

同じアドレスのまま ひとつのアドレスだけで

演算できた!😂

Page 83: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

83

パッケージ

package main

import "fmt"

func main() { fmt.Println("Hello") }

import文 他のパッケージを使えるように

Page 84: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

84

パッケージ

package main

import ( "fmt" "math" )

func main() { fmt.Println("Pi =", math.Pi) }

複数import 丸括弧()で

Printlnの使い方 ,区切りで変数を入れることが出来る

Page 85: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

85

パッケージ自分のパッケージを作る

Page 86: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

86

パッケージ

package mypackage

import "fmt"

func Hello() { fmt.Println("Hello!") }

自分のパッケージを作るhello.go

Page 87: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

87

パッケージ

package main

import ( "fmt" "./mypackage" )

func main() { mypackage.Hello() fmt.Println("World!") }

自分のパッケージを作るmain.go

手元のパッケージ ./から始めること

Page 88: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

88

パッケージgithub上のパッケージ

$ go get github.com/iwamatsu0430/hwgo

github上のパッケージをDLしてくれる

https://github.com/iwamatsu0430/hwgo

$ ./go get github.com/iwamatsu0430/hwgo

Page 89: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

89

パッケージgithub上のパッケージ

package main

import "github.com/iwamatsu0430/hwgo"

func main() { hwgo.Hello() hwgo.World() hwgo.Say("A Happy New Year 2017!") }

Page 90: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

90

パッケージ紹介

https://golang.org/pkg/

標準パッケージ

Page 91: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

91

パッケージ紹介

http://go-search.org/

パッケージ検索

Page 92: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

92

パッケージ紹介

https://godoc.org/

人気パッケージ

Page 93: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第一部Golang Introduction

93

パッケージ紹介

巨人の肩の上に乗ろう!

Page 94: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部 WEBサーバを作ろう!

Page 95: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

ざっくりWEB

Page 96: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

96

ざっくりWEB

HTML CSS JavaScript

それぞれフォーマットが定められている

① WEBサイトのコンテンツ

Page 97: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

97

ざっくりWEB② コンテンツの送信

HTML CSS JavaScript

同様にHTMLやCSS、JavaScriptの 送り方にもフォーマットが定められている

Page 98: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

98

ざっくりWEB③ コンテンツのリクエスト

コンテンツをリクエストする際の フォーマットも定められている

hrmos.co ください

Page 99: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

99

ざっくりWEB④ 接続

そもそもリクエストをする前の ユーザとサーバの接続にも決め事がある

WEBはたくさんの決め事(プロトコル) の上で成り立っている

Page 100: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

100

ざっくりWEB

逆に言えばプロトコルを遵守すれば 自分たちでWEBが作れる!💪

Page 101: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

OSI参照モデル

Page 102: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

102

OSI参照モデル第七層 アプリケーション層 HTTP,SMTPなど

第六層 プレゼンテーション層 SMTP,FTPなど

第五層 セッション層 TLS,NetBIOSなど

第四層 トランスポート層 TCP,UDPなど

第三層 ネットワーク層 IP,ARP,ICMPなど

第二層 データリンク層 PPP,Ethernetなど

第一層 物理層 光ケーブル,無線など

あくまで参考

Page 103: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

103

OSI参照モデル第七層 アプリケーション層 HTTP,SMTPなど

第六層 プレゼンテーション層 SMTP,FTPなど

第五層 セッション層 TLS,NetBIOSなど

第四層 トランスポート層 TCP,UDPなど

第三層 ネットワーク層 IP,ARP,ICMPなど

第二層 データリンク層 PPP,Ethernetなど

第一層 物理層 光ケーブル,無線など

あくまで参考

①HTMLとか 多分この辺

Page 104: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

104

OSI参照モデル第七層 アプリケーション層 HTTP,SMTPなど

第六層 プレゼンテーション層 SMTP,FTPなど

第五層 セッション層 TLS,NetBIOSなど

第四層 トランスポート層 TCP,UDPなど

第三層 ネットワーク層 IP,ARP,ICMPなど

第二層 データリンク層 PPP,Ethernetなど

第一層 物理層 光ケーブル,無線など

あくまで参考

②③HTTP どういうフォーマット(プロトコル)で

送受信するか定義

Page 105: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

105

OSI参照モデル第七層 アプリケーション層 HTTP,SMTPなど

第六層 プレゼンテーション層 SMTP,FTPなど

第五層 セッション層 TLS,NetBIOSなど

第四層 トランスポート層 TCP,UDPなど

第三層 ネットワーク層 IP,ARP,ICMPなど

第二層 データリンク層 PPP,Ethernetなど

第一層 物理層 光ケーブル,無線など

あくまで参考

④接続 この層より下が当てはまる

Page 106: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

106

OSI参照モデル第七層 アプリケーション層 HTTP,SMTPなど

第六層 プレゼンテーション層 SMTP,FTPなど

第五層 セッション層 TLS,NetBIOSなど

第四層 トランスポート層 TCP,UDPなど

第三層 ネットワーク層 IP,ARP,ICMPなど

第二層 データリンク層 PPP,Ethernetなど

第一層 物理層 光ケーブル,無線など

以上の部分を自分たちで実装してみる

Page 107: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

簡単なレスポンスを返そう

Page 108: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

108

簡単なレスポンスを返そう

package main

import ( "fmt" "net" "os" )

func checkError(err error) { if err != nil { os.Exit(1) } }

エラーチェック エラーになっている場合、 プログラムを終了する

エラー型 Go言語標準の型 エラー情報を持つ

Page 109: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

109

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

fmt.Print("accepting ... ") conn, err := listener.Accept() defer conn.Close() if err == nil { fmt.Println("!") conn.Write([]byte("hello")) conn.Write([]byte("\r\n")) } }

Page 110: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

110

簡単なレスポンスを返そう

とりあえずなんか返ってきた👏

$ curl -v http://localhost:5555

Page 111: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

111

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

fmt.Print("accepting ... ") conn, err := listener.Accept() defer conn.Close() if err == nil { fmt.Println("!") conn.Write([]byte("hello")) conn.Write([]byte("\r\n")) } }

TCPアドレスへ IPv4のアドレス情報(構造体)へ

パースする

エラーチェック パースに失敗したら終了

アドレスの指定 省略形だが、localhostの

5555ポートを使用するという意味

Page 112: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

112

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

fmt.Print("accepting ... ") conn, err := listener.Accept() defer conn.Close() if err == nil { fmt.Println("!") conn.Write([]byte("hello")) conn.Write([]byte("\r\n")) } }

ポートの確保 既に使用されていれば ここでエラーとなる

Page 113: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

113

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

fmt.Print("accepting ... ") conn, err := listener.Accept() defer conn.Close() if err == nil { fmt.Println("!") conn.Write([]byte("hello")) conn.Write([]byte("\r\n")) } }

接続待ち クライアントからの接続を

待ち続ける

defer メソッド終了時に必ず呼ばれる

Page 114: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

114

簡単なレスポンスを返そう

panicとdefer

package main

import "fmt"

func main() { hello() }

func hello() { defer fmt.Println("defered") }

defer メソッド終了時に必ず呼ばれる

Page 115: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

115

簡単なレスポンスを返そう

panicとdefer

package main

import "fmt"

func main() { hello() }

func hello() { defer fmt.Println(“defered") panic("Runtime Error") }

panic 実行時エラーの呼び出し

何らかの理由で発生することはある

Page 116: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

116

簡単なレスポンスを返そう

panicとdefer

エラーの後もdeferが動く💪

Page 117: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

117

簡単なレスポンスを返そう

panicとdeferとrecover

package main

import "fmt"

func main() { hello() fmt.Println("I'm alive") }

func hello() { defer fmt.Println("defered") panic("Runtime Error") }

Page 118: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

118

簡単なレスポンスを返そう

panicとdeferとrecover

処理は続かない😢

Page 119: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

119

簡単なレスポンスを返そう

panicとdeferとrecoverpackage main

import "fmt"

func main() { hello() fmt.Println("I'm alive") }

func hello() { defer func(){ fmt.Println("defered") recover() }() panic("Runtime Error") }

recover panicからの復旧

errorの内容も返してくれる

Page 120: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

120

簡単なレスポンスを返そう

panicとdeferとrecover

処理が続いた!☺

Page 121: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

121

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

fmt.Print("accepting ... ") conn, err := listener.Accept() defer conn.Close() if err == nil { fmt.Println("!") conn.Write([]byte("hello")) conn.Write([]byte("\r\n")) } }

キャスト バイト配列へキャストしている

型名(値)

レスポンス出力 バイト配列が必要

改行コード 出力の終わりを明示している

Page 122: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

122

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

fmt.Print("accepting ... ") conn, err := listener.Accept() defer conn.Close() if err == nil { fmt.Println("!") conn.Write([]byte("hello")) conn.Write([]byte("\r\n")) } }

キャスト バイト配列へキャストしている

型名(値)

UTF-8となる 他の文字コードを扱う場合は 別途パッケージが必要になる

Page 123: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

123

簡単なレスポンスを返そう

func listen(listener *net.TCPListener) { fmt.Print("accepting ... ") conn, err := listener.Accept() defer conn.Close() if err == nil { fmt.Println("!") conn.Write([]byte("hello")) conn.Write([]byte("\r\n")) } }

処理の切り出し

Page 124: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

124

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { listen(listener) } }

永続化

Page 125: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

125

簡単なレスポンスを返そう

func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":5555") checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err)

for { listen(listener) } }

永続化

forを利用 無限ループにしてやる

Page 126: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

126

簡単なレスポンスを返そう

何度でもレスポンスが返せるように☺

Page 127: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

RFCを読んでみよう

Page 128: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

128

RFCを読んでみようブラウザからアクセス

まだHTTPじゃない😭

Page 129: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

129

RFCを読んでみよう

Page 130: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

130

RFCを読んでみよう

必要なことは大体書いてある😂

Page 131: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

HTMLを返そう

Page 132: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

132

HTMLを返そう

この時間でRFCを見るのは流石にきついので…

$ curl -v https://hrmos.co

curlでレスポンスを見て、真似てみよう

とはいえ…

Page 133: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

133

HTMLを返そう

サーバサイドの方は 周りのフォローお願いします🙇

15:35まで!

Page 134: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

HTMLを返そう 模範解答

Page 135: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

135

HTMLを返そう 模範解答

import ( "fmt" "net" "os" "strconv" ) strconv

文字列変換などのパッケージ

Page 136: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

136

HTMLを返そう 模範解答

func createHtml() ([]byte, int) { content := []byte(`<html> <body> <h1>Hello, My WEB Server!</h1> </body> </html>`) return content, len(content) }

バッククウォート `で文字列を囲むと

改行などをそのまま扱える

Page 137: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

137

HTMLを返そう 模範解答

func listen(listener *net.TCPListener) { conn, err := listener.Accept() defer conn.Close() if err == nil { content, contentLength := createHtml() header := "HTTP/1.1 200 OK" header += "\r\n" header += "Content-Type: text/html" header += "\r\n" header += "Content-Length: " + strconv.Itoa(contentLength) header += "\r\n" header += "\r\n" conn.Write([]byte(header)) conn.Write(content) conn.Write([]byte("\r\n")) } }

int => string 暗黙的な変換はない

Page 138: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

138

HTMLを返そう 模範解答

ブラウザからアクセス

表示された!😉

Page 139: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

ファイルを返そう

Page 140: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

140

ファイルを返そう

適当なHTMLファイルを準備

$ echo "<html><body>I am File</body></html>" > index.html

このファイルを読み取り、返せるようにする

Page 141: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

141

ファイルを返そう勘所

ファイルを開く

file, err = os.Open(“./index.html")

ファイルの読み込み

for { bytes := make([]byte, 1024) _, err := file.Read(bytes) if err != nil { break } }

Page 142: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

142

ファイルを返そう勘所

ファイルを開く

file, err = os.Open(“./index.html")

ファイルの読み込み

for { bytes := make([]byte, 1024) _, err := file.Read(bytes) if err != nil { break } }

読み込みバッファ 1024バイトずつ読み込む

Page 143: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

143

ファイルを返そう勘所

ファイルを開く

file, err = os.Open(“./index.html")

ファイルの読み込み

for { bytes := make([]byte, 1024) _, err := file.Read(bytes) if err != nil { break } }

Read bytesに読み込まれたデータが

入ってくる

Page 144: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

144

ファイルを返そう勘所

ファイルを開く

file, err = os.Open(“./index.html")

ファイルの読み込み

for { bytes := make([]byte, 1024) _, err := file.Read(bytes) if err != nil { break } }

返り値 1つ目の返り値には、実際に

読み込んだデータのサイズが入る

Page 145: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

145

ファイルを返そう勘所

ファイルを開く

file, err = os.Open(“./index.html")

ファイルの読み込み

for { bytes := make([]byte, 1024) _, err := file.Read(bytes) if err != nil { break } }

ファイルの終わり 全て読み込むまでループ

Page 146: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

146

ファイルを返そう読み込みイメージ

バッファ(1024byte)

ファイル(???byte)

Page 147: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

147

ファイルを返そう読み込みイメージ

バッファ(1024byte)

ファイル(???byte)読み込み 1024byte

Page 148: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

148

ファイルを返そう読み込みイメージ

バッファ(1024byte)

ファイル(???byte)読み込み 1024byte

Page 149: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

149

ファイルを返そう読み込みイメージ

バッファ(1024byte)

ファイル(???byte)読み込み 1024byte

Page 150: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

150

ファイルを返そう読み込みイメージ

バッファ(1024byte)

ファイル(???byte)読み込み 1024byte

Page 151: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

151

ファイルを返そう読み込みイメージ

バッファ(1024byte)

ファイル(???byte)読み込み終了 これ以上読み込めない

Page 152: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

152

ファイルを返そう

サーバサイドの方は 周りのフォローお願いします🙇

16:10まで!

Page 153: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

ファイルを返そう 模範解答

Page 154: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

154

ファイルを返そう 模範解答

func createHtml() (content []byte, contentLength int) { file, err := os.Open("./index.html") if err != nil { return } for { bytes := make([]byte, 1024) length, err := file.Read(bytes) content = append(content, bytes…) contentLength += length if err != nil { break } } return }

Page 155: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

155

ファイルを返そう 模範解答

ブラウザからアクセス

表示された!😉

Page 156: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

リクエストをパース

Page 157: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

157

リクエストをパース

コンテンツをリクエストする際の フォーマットも定められている

index.html ください

style.css ください

Page 158: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

158

リクエストをパース

index.html ください

style.css ください

適切なファイルを返せるようにしよう

Page 159: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

159

リクエストをパース勘所

for { bytes := make([]byte, 1024) length, err := conn.Read(bytes) }

ファイルの読み込みとほぼ同じ!

Page 160: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

160

リクエストをパース勘所

[]byte => string

string(bytes)

文字列を改行で分割

import “strings"

strings.Split(str, "\n")

Page 161: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

161

リクエストをパース

サーバサイドの方は 周りのフォローお願いします🙇

16:50まで!

Page 162: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

リクエストをパース 模範解答

Page 163: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

163

リクエストをパース 模範解答

import ( "bytes" "net" "os" "strconv" )

func readRequest(conn net.Conn) (request []byte) { for { bytes := make([]byte, 1024) length, _ := conn.Read(bytes) request = append(request, bytes...) if length < 1024 { return } } }

Page 164: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

164

リクエストをパース 模範解答

func getTarget(request []byte) (target string) { rows := bytes.Split(request, []byte("\r\n")) if len(rows) > 0 { params := bytes.Split(rows[0], []byte(" ")) if len(params) >= 2 { target = string(params[1]) } } return }

バイト配列のSplit stringに戻さなくても

色々処理できる

Page 165: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

165

リクエストをパース 模範解答

func loadFile(target string) (content []byte, contentLength int) { file, err := os.Open("." + target) if err != nil { return } for { bytes := make([]byte, 1024) length, err := file.Read(bytes) content = append(content, bytes...) contentLength += length if err != nil { break } } return }

Page 166: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

166

リクエストをパース 模範解答

func createHeader(contentLength int) (header string) { header += "HTTP/1.1 200 OK" header += "\r\n" header += "Content-Type: text/html" header += "\r\n" header += "Content-Length: " + strconv.Itoa(contentLength) header += "\r\n" header += "\r\n" return }

Page 167: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

167

リクエストをパース 模範解答

func listen(listener *net.TCPListener) { conn, err := listener.Accept() defer conn.Close() request := readRequest(conn) target := getTarget(request) if err == nil { content, contentLength := loadFile(target) header := createHeader(contentLength) conn.Write([]byte(header)) conn.Write(content) conn.Write([]byte("\r\n")) } }

Page 168: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

168

リクエストをパース 模範解答

ブラウザからアクセス

簡易なWEBサーバになった😎

Page 169: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

169

リクエストをパース 模範解答

もっと改良する場合は

ファイルがない場合の処理(404)

GETやPOSTを判別できるように

POSTのパラメータを受け取ってみる

Page 170: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部 低層に触れてみよう!

Page 171: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

ざっくり低層

Page 172: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

172

ざっくり低層第七層 アプリケーション層 HTTP,SMTPなど

第六層 プレゼンテーション層 SMTP,FTPなど

第五層 セッション層 TLS,NetBIOSなど

第四層 トランスポート層 TCP,UDPなど

第三層 ネットワーク層 IP,ARP,ICMPなど

第二層 データリンク層 PPP,Ethernetなど

第一層 物理層 光ケーブル,無線など

このあたりにも挑戦…

Page 173: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

173

ざっくり低層物理層

1 or 0で電気信号が流れてくる

信号の受取 10001100…

Page 174: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

174

ざっくり低層データリンク層

これはethernet 一定のプロトコルに従っている事を

確認し情報をパース

Page 175: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

175

ざっくり低層データリンク層より↑

ethernetヘッダ IPヘッダ TCPヘッダ データ

IPヘッダ TCPヘッダ データ

TCPヘッダ データ

第二層

第三層

第四層

層と言っても単純な構造☺

Page 176: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

Pingを送ってみよう

Page 177: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第二部WEBサーバを作ろう!

177

ざっくり低層

第七層 アプリケーション層 HTTP,SMTPなど

第六層 プレゼンテーション層 SMTP,FTPなど

第五層 セッション層 TLS,NetBIOSなど

第四層 トランスポート層 TCP,UDPなど

第三層 ネットワーク層 IP,ARP,ICMPなど

第二層 データリンク層 PPP,Ethernetなど

第一層 物理層 光ケーブル,無線など

Pingとは

ICMPの一種 通知タイプの一つ Echo, Echo Reply

Page 178: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

178

Pingを送ってみようPing情報の確認

package main

import ( "os" "fmt" "syscall" )

receive.go

Page 179: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

179

Pingを送ってみようPing情報の確認

func main() { fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) f := os.NewFile(uintptr(fd), fmt.Sprintf("fd %d", fd)) for { buffer := make([]byte, 1024) length, err := f.Read(buffer) if err != nil { fmt.Println(err) } fmt.Println("length:", length) fmt.Println(buffer[:length]) fmt.Printf("% X\n", buffer[:length]) fmt.Println("") } }

receive.go

Page 180: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

180

Pingを送ってみよう

$ sudo -E go run receive.go

sudo必須!

$ ping 8.8.8.8

Page 181: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

181

Pingを送ってみようEcho Replyを表示

ping 8.8.8.8 Echo Request

Page 182: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

182

Pingを送ってみようEcho Replyを表示

pingへの応答 Echo Reply

表示 自分に返信されたpingを表示

Page 183: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

183

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Version ヘッダ長 サービス種別 …

69 192 64 0 152 108 0 0 53 1 25 96 8 8 8 8 192 168 2 101 0 0 50 159 32 37 0 2 88 108 41 35 0 5 64 162 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

45 C0 40 00 98 6C 00 00 35 01 19 60 08 08 08 08 C0 A8 02 65 00 00 32 9F 20 25 00 02 58 6C 29 23 00 05 40 A2 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37

Page 184: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

184

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Version ヘッダ長 サービス種別 …

69 192 64 0 152 108 0 0 53 1 25 96 8 8 8 8 192 168 2 101 0 0 50 159 32 37 0 2 88 108 41 35 0 5 64 162 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

45 C0 40 00 98 6C 00 00 35 01 19 60 08 08 08 08 C0 A8 02 65 00 00 32 9F 20 25 00 02 58 6C 29 23 00 05 40 A2 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37

version IPv4の場合は4が入る

Page 185: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

185

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Version ヘッダ長 サービス種別 …

69 192 64 0 152 108 0 0 53 1 25 96 8 8 8 8 192 168 2 101 0 0 50 159 32 37 0 2 88 108 41 35 0 5 64 162 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

45 C0 40 00 98 6C 00 00 35 01 19 60 08 08 08 08 C0 A8 02 65 00 00 32 9F 20 25 00 02 58 6C 29 23 00 05 40 A2 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37

ヘッダ長 通常は5が入る

Page 186: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

186

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Version ヘッダ長 サービス種別 …

69 192 64 0 152 108 0 0 53 1 25 96 8 8 8 8 192 168 2 101 0 0 50 159 32 37 0 2 88 108 41 35 0 5 64 162 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

45 C0 40 00 98 6C 00 00 35 01 19 60 08 08 08 08 C0 A8 02 65 00 00 32 9F 20 25 00 02 58 6C 29 23 00 05 40 A2 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37

サービス種別 Echo Reply

Page 187: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

187

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Version ヘッダ長 サービス種別 …

69 192 64 0 152 108 0 0 53 1 25 96 8 8 8 8 192 168 2 101 0 0 50 159 32 37 0 2 88 108 41 35 0 5 64 162 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

45 C0 40 00 98 6C 00 00 35 01 19 60 08 08 08 08 C0 A8 02 65 00 00 32 9F 20 25 00 02 58 6C 29 23 00 05 40 A2 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37

送信元アドレス 先程のping送信先と一致

Page 188: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

188

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Version ヘッダ長 サービス種別 …

69 192 64 0 152 108 0 0 53 1 25 96 8 8 8 8 192 168 2 101 0 0 50 159 32 37 0 2 88 108 41 35 0 5 64 162 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

45 C0 40 00 98 6C 00 00 35 01 19 60 08 08 08 08 C0 A8 02 65 00 00 32 9F 20 25 00 02 58 6C 29 23 00 05 40 A2 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37

宛先アドレス 自身のIPアドレスと一致

Page 189: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

189

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Type Code CheckSum …

69 192 40 0 197 103 0 0 64 1 46 227 192 168 2 1 192 168 2 101 3 3 130 209 0 0 0 0 69 0 32 0 79 255 0 0 64 17 165 23 192 168 2 101 192 168 2 1 199 102 0 192 0 12 166 231 8 1 3 16

45 C0 28 00 C5 67 00 00 40 01 2E E3 C0 A8 02 01 C0 A8 02 65 03 03 82 D1 00 00 00 00 45 00 20 00 4F FF 00 00 40 11 A5 17 C0 A8 02 65 C0 A8 02 01 C7 66 00 C0 00 0C A6 E7 08 01 03 10

Page 190: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

190

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Type Code CheckSum …

69 192 40 0 197 103 0 0 64 1 46 227 192 168 2 1 192 168 2 101 3 3 130 209 0 0 0 0 69 0 32 0 79 255 0 0 64 17 165 23 192 168 2 101 192 168 2 1 199 102 0 192 0 12 166 231 8 1 3 16

45 C0 28 00 C5 67 00 00 40 01 2E E3 C0 A8 02 01 C0 A8 02 65 03 03 82 D1 00 00 00 00 45 00 20 00 4F FF 00 00 40 11 A5 17 C0 A8 02 65 C0 A8 02 01 C7 66 00 C0 00 0C A6 E7 08 01 03 10

Type Replyの場合は0

Page 191: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

191

Pingを送ってみようパケットの構成

MACヘッダ IPヘッダ ICMPヘッダ データ

青色の部分が取得できている

Type Code CheckSum …

69 192 40 0 197 103 0 0 64 1 46 227 192 168 2 1 192 168 2 101 3 3 130 209 0 0 0 0 69 0 32 0 79 255 0 0 64 17 165 23 192 168 2 101 192 168 2 1 199 102 0 192 0 12 166 231 8 1 3 16

45 C0 28 00 C5 67 00 00 40 01 2E E3 C0 A8 02 01 C0 A8 02 65 03 03 82 D1 00 00 00 00 45 00 20 00 4F FF 00 00 40 11 A5 17 C0 A8 02 65 C0 A8 02 01 C7 66 00 C0 00 0C A6 E7 08 01 03 10

Code こちらも0が入る

Page 192: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

192

Pingを送ってみようPingの送信

import ( "encoding/binary" "fmt" "net" "os" "time" "syscall" "golang.org/x/net/ipv4" )

send.go

$ go get golang.org/x/net/ipv4

Page 193: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

193

Pingを送ってみようPingの送信

func checksum(b []byte) uint16 { count := len(b) sum := uint32(0) for i := 0; i < count-1; i += 2 { sum += uint32(b[i])<<8 | uint32(b[i+1]) } if count&1 != 0 { sum += uint32(b[count-1]) << 8 } for (sum >> 16) > 0 { sum = (sum & 0xffff) + (sum >> 16) } return ^(uint16(sum)) }

send.go

<< >> シフト演算子

5(101) << 2 => 20(10100)

Page 194: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

194

Pingを送ってみようPingの送信

func createICMPPackets() []byte { now := time.Now() tb, _ := now.MarshalBinary() icmp := make([]byte, 8+len(tb)) icmp[0] = byte(8) icmp[1] = byte(0) binary.BigEndian.PutUint16(icmp[4:6], uint16(os.Getpid() & 0xffff)) binary.BigEndian.PutUint16(icmp[6:8], uint16(0)) copy(icmp[8:], tb) cs := checksum(icmp) icmp[2] = byte(cs >> 8) icmp[3] = byte(cs) return icmp }

send.go

現在時刻 受信処理とセットにすれば送信に かかった時間を求められる(未対応)

Page 195: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

195

Pingを送ってみようPingの送信

func createPackets() []byte { icmp := createICMPPackets() header := ipv4.Header{ Version: 4, Len: 20, TotalLen: 20 + len(icmp), TTL: 64, Protocol: 1, Dst: net.IPv4(127, 0, 0, 1), } headerBytes, _ := header.Marshal() return append(headerBytes, icmp...) }

send.go

IPヘッダ IPヘッダ用の構造体(Map)があるので

利用する

Marshal 構造体からバイト配列へ変換

Page 196: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

196

Pingを送ってみようPingの送信

func main() { fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW) syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)

addr := syscall.SockaddrInet4{ Port: 0, Addr: [4]byte{127, 0, 0, 1}, }

packets := createPackets() err := syscall.Sendto(fd, packets, 0, &addr) if err != nil { fmt.Println("Sendto:", err) } }

send.go

謎のおまじない… システムコールで何をしているか まだちょっと分かっていません🙇

Page 197: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

197

Pingを送ってみようPingの送信

$ sudo -E go receive.go

$ sudo -E go send.go

返ってきた!😂

Page 198: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

第三部低層に触れてみよう!

198

Pingを送ってみようTCPも自分で作れそう…?

とても大変そうなので断念😱

Page 199: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

199

まとめ

Go言語にざっくり慣れられた?

WEBサーバをなんとなく作れた!

各自ブラッシュアップしてもられば!

Page 200: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

ありがとうございました!

Page 201: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

201

Credit

https://github.com/tenntenn/gopher-stickers

Gopher Stickers

The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) The gopher stickers was made by Takuya Ueda (https://twitter.com/tenntenn). Licensed under the Creative Commons 3.0 Attributions license.

Page 202: 20170104 go publish...22 Hello World package main import "fmt" func main() { fmt.Println(“Hello, World!”) } $ go run main.go Println関数 console.log, printlnと同じ

202

Credit

Raw sockets in Go: Link layerhttp://www.darkcoding.net/software/raw-sockets-in-go-link-layer/

Go で pinghttp://tyamagu2.xyz/articles/go_ping/