GoでTCPとUDPを比較してみた

この記事は 東京理科大学 Advent Calendar 2018 6日目の記事です。

はじめに

今回Goのnetパッケージを使ってTCPソケット通信を扱う機会があったので、同じnetパッケージで扱うことのできるUDPソケット通信と比較してみました。

比較方法

クライアント側からサーバ側にhelloとたくさん送り、そのまま出力した時の両者の違いをみます。

TCPソケット通信

TCPによる通信ではデータをバイトストリームと呼ばれるbyte型のひと続きのデータとして扱います。

・クライアント

クライアントのコードは以下です。

package main

import (
	"log"
	"net"
)

func main() {
	conn, err := net.Dial("tcp", "localhost:8088")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	// メッセージを送信する
	for {
		msg := "hello"
		conn.Write([]byte(msg))
	}
}

・サーバ

サーバのコードは以下です。

package main

import (
	"fmt"
	"log"
	"net"
)

func main() {
	listener, err := net.Listen("tcp", "localhost:8088")
	if err != nil {
		log.Fatal(err)
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err)
			continue
		}
		defer conn.Close()

		go handleconn(conn)
	}
}

func handleconn(conn net.Conn) {
	buf := make([]byte, 1024) // 1024バイトのスライスを用意
	// 送られてきたメッセージを出力
	for {
		n, _ := conn.Read(buf)
		fmt.Println(string(buf[:n]))
	}
}

実行結果

$ go run tcp_server.go
hellohellohellohellohellohellohellohellohello
hellohellohellohellohellohello
hello
hellohellohellohello
hellohello
hello
hello
hello
...

UDPソケット通信

UDPによる通信ではデータを独立したパケットのデータグラムとして扱います。

・クライアント

クライアントのコードは以下です。

package main

import (
	"log"
	"net"
)

func main() {
	conn, err := net.Dial("udp", "localhost:8088")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	// メッセージを送信する
	for {
		msg := "hello"
		conn.Write([]byte(msg))
	}
}

・サーバ

サーバのコードは以下です。

package main

import (
	"fmt"
	"log"
	"net"
)

func main() {
	udpAddr, err := net.ResolveUDPAddr("udp", ":8088")
	if err != nil {
		log.Fatal(err)
	}
	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		log.Fatal(err)
	}
	for {
		defer conn.Close()

		go handleconn(conn)
	}
}

func handleconn(conn *net.UDPConn) {
	buf := make([]byte, 1024) // 1024バイトのスライス
	// 送られてきたメッセージを出力
	for {
		n, _ := conn.Read(buf)
		fmt.Println(string(buf[:n]))
	}
}

実行結果

$ go run udp_server.go
hello
hello
hello
hello
hello
hello
hello
hello
...

まとめ

以上の結果から、TCPではデータをストリームとして扱っているので何も処理をせずにそのまま出力した場合はhelloという文字列が連結されて出力される場合があることがわかった。 また、UDPではデータをパケットごとにデータグラムとして扱っているためそのまま出力してもhelloという文字列が区切られて出力されることがわかった。

蛇足

UDPと同じ出力結果になるようにTCPで処理をしようとした場合、 データの末尾に\nなどの区切り文字を用意する データのヘッダにデータのバイト数をつけて送信する ことで処理ができます。

Go