IPv4 によるブロードキャスト

## 1. 概要
この記事では、IPv4 によるブロードキャスト実現のための Golang サンプルコード投稿します。

## 2. はじめに
前回までの記事では、IPv4 や IPv6 によるマルチキャストの記事を投稿しました。

* [IPv4 によるマルチキャスト](https://qiita.com/KyojiOsada/items/bc381b3058715d4011d2)
* [IPv6 によるマルチキャスト](https://qiita.com/KyojiOsada/items/714a6e352707429882e1)
* [IPv4 マルチキャストによるフェイルオーバー](https://qiita.com/KyojiOsada/items/1f8253b93623f2267509)
* [IPv4 マルチキャストによる自律ネットワークシステムの構築](https://qiita.com/KyojiOsada/items/d00dcc2c5275d3edc8ce)

![cast_type.png](https://qiita-image-store.s3.amazonaws.com/0/260161/11067e08-3a0b-eb87-3458-9929544772e0.png)

今回の記事では、IPv4 によるブロードキャスト実現のための Golang サンプルコードにより、以下 2 パターンのアドレスを使用して動作の検証を行います。

* ブロードキャストアドレス [^1]（192.0.2.255/24）
* ネットワークアドレス[^2]（192.0.2.0/24）

ブロードキャストは、マルチキャスト同様、UDP 通信となり、送信ノードの処理コスト削減にはとても有用ですが、特にブロードキャストの場合には、ネットワークコストや中継ノードのコスト増になるケースもありますので、適宜最適なキャストタイプの選択をした設計が必要でしょう。

## 3. 環境
* RHEL-7 系
* Go 1.9

## 4. 構成
* node1
  * 192.0.2.1/24
* node2
  * 192.0.2.2/24

## 5. Golang サンプルコード
@ node1, 2
`$ sudo nvim ~/go/broadcast_ipv4.go`

```go:~/go/broadcast_ipv4.go
package main

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

var InboundToAddr string = "" // 動作検証で切り替えます
var OutboundFromAddr string = "" // 動作検証で切り替えます
var OutboundToAddr string = "" // 動作検証で切り替えます
var BufferByte int = 64
var IntervalSeconds int = 1

func main() {

	// Start inbound
	go func() {
		inbound_to_addr_byte, err := net.ResolveUDPAddr("udp", InboundToAddr)
		Error(err)

		inbound, err := net.ListenUDP("udp", inbound_to_addr_byte)
		Error(err)
		defer inbound.Close()
		fmt.Printf("Listened *:* > %s\n", InboundToAddr)

		buffer := make([]byte, BufferByte)
		for {
			// Inbound message
			length, inbound_from_addr_byte, err := inbound.ReadFrom(buffer)
			Error(err)
			inbound_message := string(buffer[:length])

			inbound_from_addr := inbound_from_addr_byte.(*net.UDPAddr).String()

			fmt.Printf("Inbound %v > %v as “%s”\n", inbound_from_addr, InboundToAddr, inbound_message)
		}
	}()

	// Start outbound
	outbound_from_addr, err := net.ResolveUDPAddr("udp", OutboundFromAddr)
	outbound_to_addr, err := net.ResolveUDPAddr("udp", OutboundToAddr)
	outbound, err := net.DialUDP("udp", outbound_from_addr, outbound_to_addr)
	Error(err)
	defer outbound.Close()
	fmt.Printf("Connected %s > %s\n", OutboundFromAddr, OutboundToAddr)

	// Get hostname
	outbound_message, err := os.Hostname()
	Error(err)

	for {
		time.Sleep(time.Duration(IntervalSeconds) * time.Second)

		// Outbound message
		outbound.Write([]byte(outbound_message))
		fmt.Printf("Outbound %v > %v as “%s”\n", outbound_from_addr, outbound_to_addr, outbound_message)
	}

}

func Error(_err error) {
	if _err != nil {
		panic(_err)
	}
}
```


## 6. Golang サンプル実行
以下では、ブロードキャストアドレスへの送受信と、ネットワークアドレスへの送受信のパターンの動作検証をします。

### 6-1. ブロードキャストアドレス
ブロードキャストアドレスへの送受信の動作検証を実施します。

@ node1
送信： 192.0.2.1:56789　>　192.0.2.255:56789
受信： all　>　192.0.2.255:56789
`$ sudo nvim ~/go/broadcast_ipv4.go`

```go:~/go/broadcast_ipv4.go
var InboundToAddr string = "192.0.2.255:56789" // ブロードキャストアドレス
var OutboundFromAddr string = "192.0.2.1:56789"
var OutboundToAddr string = "192.0.2.255:56789" // ブロードキャストアドレス
```

@ node2
送信： 192.0.2.2:56789　>　192.0.2.255:56789
受信： all　>　192.0.2.255:56789
`$ sudo nvim ~/go/broadcast_ipv4.go`

```go:~/go/broadcast_ipv4.go
var InboundToAddr string = "192.0.2.255:56789" // ブロードキャストアドレス
var OutboundFromAddr string = "192.0.2.2:56789"
var OutboundToAddr string = "192.0.2.255:56789" // ブロードキャストアドレス
```

@ node1
受信成功

```
[user@node1 ~/go]$ sudo go run broadcast_ipv4.go
Connected 192.0.2.1:56789 > 192.0.2.255:56789
Listened *:* > 192.0.2.255:56789
Outbound 192.0.2.1:56789 > 192.0.2.255:56789 as “node1”
Inbound 192.0.2.1:56789 > 192.0.2.255:56789 as “node1”
Inbound 192.0.2.2:56789 > 192.0.2.255:56789 as “node2”
...
```

@ node2
受信成功

```
[user@node2 ~/go]$ sudo go run broadcast_ipv4.go
Connected 192.0.2.2:56789 > 192.0.2.255:56789
Listened *:* > 192.0.2.255:56789
Outbound 192.0.2.2:56789 > 192.0.2.255:56789 as “node2”
Inbound 192.0.2.1:56789 > 192.0.2.255:56789 as “node1”
Inbound 192.0.2.2:56789 > 192.0.2.255:56789 as “node2”
...
```

### 6-2. ネットワークアドレス
ネットワークアドレスへの送受信の動作検証を実施します。

@ node1
送信： 192.0.2.1:56789　>　192.0.2.0:56789
受信： all　>　192.0.2.0:56789
`$ sudo nvim ~/go/broadcast_ipv4.go`

```go:~/go/broadcast_ipv4.go
var InboundToAddr string = "192.0.2.0:56789" // ネットワークアドレス
var OutboundFromAddr string = "192.0.2.1:56789"
var OutboundToAddr string = "192.0.2.0:56789" // ネットワークアドレス
```

@ node2
送信： 192.0.2.2:56789　>　192.0.2.0:56789
受信： all　>　192.0.2.0:56789
`$ sudo nvim ~/go/broadcast_ipv4.go`

```go:~/go/broadcast_ipv4.go
var InboundToAddr string = "192.0.2.0:56789" // ネットワークアドレス
var OutboundFromAddr string = "192.0.2.2:56789"
var OutboundToAddr string = "192.0.2.0:56789" // ネットワークアドレス
```

@ node1
受信成功

```
[user@node1 ~/go]$ sudo go run broadcast_ipv4.go
Connected 192.0.2.1:56789 > 192.0.2.0:56789
Listened *:* > 192.0.2.0:56789
Outbound 192.0.2.1:56789 > 192.0.2.0:56789 as “node1”
Inbound 192.0.2.1:56789 > 192.0.2.0:56789 as “node1”
Inbound 192.0.2.2:56789 > 192.0.2.0:56789 as “node2”
...
```

@ node2
受信成功

```
[user@node2 ~/go]$ sudo go run broadcast_ipv4.go
Connected 192.0.2.2:56789 > 192.0.2.0:56789
Listened *:* > 192.0.2.255:56789
Outbound 192.0.2.2:56789 > 192.0.2.0:56789 as “node2”
Inbound 192.0.2.1:56789 > 192.0.2.0:56789 as “node1”
Inbound 192.0.2.2:56789 > 192.0.2.0:56789 as “node2”
...
```

## 7. まとめ
この記事では、IPv4 によるブロードキャスト実現のための Golang サンプルコード投稿しました。
このように、ブロードキャストアドレスやネットワークアドレスの利用により、サブネット内におけるブロードキャストが実現可能となります。
また、マルチキャストと同様、ブロードキャストも UDP 通信となり、送信ノードの処理コスト削減にはとても有用ですが、特にブロードキャストの場合には、ネットワークコストや中継ノードのコスト増になるケースもありますので、適宜最適なキャストタイプの選択をした設計が必要でしょう。

[^1]: [ブロードキャストアドレスとは？](https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%AD%E3%83%BC%E3%83%89%E3%82%AD%E3%83%A3%E3%82%B9%E3%83%88%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9)
[^2]: [ネットワークアドレスとは？](https://ja.wikipedia.org/wiki/%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9)