🛰️

GoでTCP サーバ/クライアントを動かしてみた

2022/09/23に公開

Goを使って、TCP通信でサーバー⇄クライアント間でTCP通信を行なっていきたいと思います。
Goにには、標準でnetパッケージというものが用意されているので今回はこちらを使用します。

TCPとは

TCPとは、信頼性の高い通信を実現するために使用されるプロトコルになります。IPと同様にインターネットにおいて標準的に利用されています。TCPは、IPの上位プロトコルでトランスポート層で動作するプロトコルで、ネットワーク層のIPとセッション層以上のプロトコルの橋渡しをする形で動作しています。

TCPソケット

TCP/IPアプリケーションを作成するための抽象化されたインターフェースのことです。
互いのソケットをネットワークを通して接続し、通信をすることが可能となります。

サーバー側の実装

server.go
package main

import (
	"io"
	"log"
	"net"
	"time"
)

func receiveTCPConn(ln *net.TCPListener) {
	for {
		err := ln.SetDeadline(time.Now().Add(time.Second * 10))
		if err != nil {
			log.Fatal(err)
		}
		conn, err := ln.AcceptTCP()
		if err != nil {
			log.Fatal(err)
		}
		go echoHandler(conn)
	}
}

func echoHandler(conn *net.TCPConn) {
	defer conn.Close()
	for {
		_, err := io.WriteString(conn, "Socket Connection!!\n")
		if err != nil {
			return
		}
		time.Sleep(time.Second)
	}
}

func main() {
	tcpAddr, err := net.ResolveTCPAddr("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}

	ln, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		log.Fatal(err)
	}
	receiveTCPConn(ln)
}

net.ResolveTCPAddr()メソッドを使用し、ソケットの作成とアドレスとポートのバインドを行いますnet.ListenTCP()メソッドで、リッスン。
AcceptTCP()メソッドで、クライアントからの接続を待ち受けます。
作成したechoHandlerに接続情報を渡します。リクエストを受けたら、Socket Connection!!を返しますようにしてます。ゴルーチンを使用してるのは、1つのリクエストの処理が完了するまでブロックされるので、別スレッドで実行し複数リクエストに対応するためです。

クライアント側の実装

クライアント側の実装を行なっていきます。

client.go
package main

import (
	"io"
	"log"
	"net"
	"os"
)

func response(dst io.Writer, src io.Reader) {
	if _, err := io.Copy(dst, src); err != nil {
		log.Fatal(err)
	}
}

func main() {
	conn, err := net.Dial("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	response(os.Stdout, conn)
}

net.Dial()メソッドを使用し、localhost:8080に接続します。
responseメソッドで、標準出力に、connをコピーして出力します。

$ go run server/server.go

$ go run client/client.go
Socket Connection!!
Socket Connection!!
Socket Connection!!
Socket Connection!!

通信できてますね。
ネットワークわからないって方は、まずはマスタリングTCP /IP入門編を読んでみてはいかがでしょうか。
かなりわかりやすく解説されているので、最初に勉強するにはうってつけかと思います。

Discussion