第18章 ネットワーク
ネットワークプログラミングの基本
Go言語における「ネットワークプログラミングの基本」では、ネットワーク通信の基本的な概念とGoでの実装方法を理解します。ここでは、基本的なクライアントとサーバーの例を紹介します。
TCPサーバーの作成
TCPサーバーは、指定されたポートでクライアントからの接続を待ち受け、データを送受信します。
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
// TCPサーバーをlocalhostのポート8080で起動
listener, err := net.Listen("tcp", "localhost:8080")
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
defer listener.Close()
fmt.Println("Server is listening on localhost:8080")
for {
// クライアントからの接続を待機
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting connection:", err)
continue
}
go handleConnection(conn)
}
}
// handleConnection はクライアントからの接続を処理します
func handleConnection(conn net.Conn) {
defer conn.Close()
// クライアントからのメッセージを読み込む
reader := bufio.NewReader(conn)
msg, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Error reading message:", err)
return
}
fmt.Printf("Received message: %s", msg)
// クライアントに応答を送信
conn.Write([]byte("Message received.\n"))
}
このコードでは、net.Listenを使用してTCPサーバーを起動し、`listener.Accept()`でクライアントからの接続を待ち受けます。接続が確立されると、handleConnection関数が新しいゴルーチンで呼び出され、クライアントからのメッセージを読み取り、応答を送信します。
TCPクライアントの作成
TCPクライアントは、サーバーに接続してデータの送受信を行います。
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
// サーバーへの接続を確立
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
fmt.Println("Error connecting to server:", err)
os.Exit(1)
}
defer conn.Close()
// サーバーにメッセージを送信
fmt.Fprint(conn, "Hello from client\n")
// サーバーからの応答を読み込む
response, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Printf("Server response: %s", response)
}
このコードでは、net.Dialを使用して指定されたアドレスのサーバーに接続し、サーバーにメッセージを送信した後、サーバーからの応答を待ち受けています。
UDPサーバーの作成
package main
import (
"fmt"
"net"
)
func main() {
// UDPサーバーを起動
addr := net.UDPAddr{
Port: 8080,
IP: net.ParseIP("127.0.0.1"),
}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
fmt.Println("UDP server listening on 127.0.0.1:8080")
// データの受信
buffer := make([]byte, 1024)
for {
n, remoteAddr, err := conn.ReadFromUDP(buffer)
if err != nil {
fmt.Println(err)
continue
}
fmt.Printf("Received: %s from %s\n", string(buffer[:n]), remoteAddr)
}
}
このサーバーは、指定されたアドレスとポートでUDPパケットを待ち受け、受信したデータをコンソールに表示します。
UDPクライアントの作成
package main
import (
"fmt"
"net"
)
func main() {
// サーバーのアドレスを設定
serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8080")
if err != nil {
fmt.Println(err)
return
}
// クライアントのUDP接続を作成
conn, err := net.DialUDP("udp", nil, serverAddr)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// サーバーにメッセージを送信
_, err = conn.Write([]byte("Hello UDP server!"))
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Message sent to UDP server")
}
UDPアドレスに対してメッセージを送信します。net.DialUDP関数を使用してUDP接続を確立し、Writeメソッドでデータを送信します。
HTTPクライアントとサーバー
Go言語における「HTTPクライアントとサーバー」の概念は、Webアプリケーション開発において非常に重要です。HTTPクライアントはサーバーにリクエストを送信し、サーバーはそれに応答します。以下に、Go言語でHTTPサーバーを構築し、クライアントからのリクエストを処理する具体的な例を示します。
HTTPサーバーの構築
Go言語のnet/httpパッケージを使用して、簡単なHTTPサーバーを構築できます。
package main
import (
"fmt"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, Go Web Server!")
}
func main() {
// ハンドラ関数をルートURLに割り当て
http.HandleFunc("/", helloHandler)
// サーバーを8080ポートで起動
fmt.Println("Server is running on http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
このコードは、ルートURL(/)にアクセスがあった際にhelloHandler関数を呼び出すように設定しています。http.ListenAndServeは、8080ポートでサーバーを起動し、リクエストを待ち受けます。
HTTPクライアントの使用
Goのnet/httpパッケージを使用して、HTTPクライアントを作成し、外部のWebサーバーにリクエストを送信できます。
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// HTTP GETリクエストを送信
response, err := http.Get("http://localhost:8080")
if err != nil {
fmt.Println("Error making GET request:", err)
return
}
defer response.Body.Close()
// レスポンスボディを読み込み
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return
}
// レスポンスボディを表示
fmt.Println("Response from server:", string(body))
}
このクライアントはhttp.Get関数を使用してhttp://localhost:8080にGETリクエストを送信し、サーバーからのレスポンスを表示します。
WEBソケット
Go言語での「Webソケット」の使用は、リアルタイム通信が必要なアプリケーションにおいて重要です。Webソケットは、サーバーとクライアント間の持続的な双方向通信を可能にします。以下に、Go言語を使用してシンプルなWebソケットサーバーとクライアントを構築する具体的な例を示します。
Webソケットサーバーの構築
Webソケットサーバーは、クライアントからのWebソケット接続を受け入れ、メッセージの送受信を行います。Goでは、github.com/gorilla/websocketパッケージが一般的に使用されます。
まず、Gorilla Websocketパッケージをインストールします。
go get github.com/gorilla/websocket
次に、Webソケットサーバーを実装します。
package main
import (
"github.com/gorilla/websocket"
"log"
"net/http"
)
var upgrader = websocket.Upgrader{} // Webソケットアップグレーダー
func websocketHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil) // HTTP接続をWebソケットにアップグレード
if err != nil {
log.Println(err)
return
}
defer conn.Close()
for {
messageType, message, err := conn.ReadMessage() // メッセージを受信
if err != nil {
log.Println("Read error:", err)
break
}
log.Printf("Received: %s", message)
// クライアントにメッセージをエコーバック
if err := conn.WriteMessage(messageType, message); err != nil {
log.Println("Write error:", err)
break
}
}
}
func main() {
http.HandleFunc("/ws", websocketHandler)
log.Println("Websocket server started on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
このコードは、/wsエンドポイントでWebソケットリクエストを受け入れ、クライアントとの通信を開始します。サーバーはクライアントからのメッセージを読み取り、そのメッセージをエコーバックします
Webソケットクライアントの実装
Webソケットクライアントは、サーバーに接続してメッセージの送受信を行います。
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Client</title>
<script type="text/javascript">
var conn;
function connect() {
conn = new WebSocket("ws://localhost:8080/ws");
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log("Received message: " + e.data);
};
conn.onerror = function(e) {
console.log("Error: ", e);
};
}
function sendMessage() {
var message = document.getElementById("message").value;
conn.send(message);
}
</script>
</head>
<body>
<button onclick="connect()">Connect</button>
<input type="text" id="message">
<button onclick="sendMessage()">Send Message</button>
</body>
</html>
このHTMLページには、「Connect」ボタンとメッセージ送信用の入力フィールドがあります。ユーザーが「Connect」ボタンをクリックすると、サーバーに対するWebソケット接続が確立され、テキストフィールドに入力されたメッセージがサーバーに送信されます。
ネットワークセキュリティ
Go言語における「ネットワークセキュリティ」は、データの安全な転送と脆弱性からの保護を目的としています。以下に、HTTPSの使用、基本認証、そして安全なデータの取り扱いに関する具体的な事例を示します。
HTTPSの使用
HTTPS(HTTP over TLS)は、データを暗号化してインターネット上で安全に転送するためのプロトコルです。Go言語では、http.ListenAndServeTLS関数を使用してHTTPSサーバーを簡単に実装できます。
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, HTTPS world!")
}
func main() {
http.HandleFunc("/", handler)
// HTTPSサーバーの起動
fmt.Println("Starting HTTPS server on :443")
err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
if err != nil {
fmt.Println("Error starting server:", err)
}
}
このコードは、証明書ファイル(server.crt)と秘密鍵ファイル(server.key)を使用してHTTPSサーバーを起動します。クライアントはこのサーバーとの間で安全な通信を行うことができます。
基本認証の実装
基本認証は、ユーザー名とパスワードを使用してHTTPリクエストの認証を行うシンプルな方法です。
func basicAuth(handler http.HandlerFunc, username, password string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok || user != username || pass != password {
w.Header().Set("WWW-Authenticate", `Basic realm="restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
handler(w, r)
}
}
func main() {
http.HandleFunc("/", basicAuth(handler, "user", "pass"))
http.ListenAndServe(":8080", nil)
}
このコードでは、ユーザー名とパスワードが正しい場合にのみリクエストを処理するbasicAuthミドルウェアを定義しています。
安全なデータの取り扱い
安全なWebアプリケーションの開発には、SQLインジェクションやクロスサイトスクリプティング(XSS)などの脆弱性を防ぐための対策が必要です。
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func queryUser(db *sql.DB, username string) {
// パラメータ化されたクエリ(SQLインジェクション対策の例)
row := db.QueryRow("SELECT * FROM users WHERE username = ?", username)
// ...
}
このコードでは、ユーザー入力を直接SQL文に埋め込む代わりに、プレースホルダーを使用し、QueryRow関数にパラメータとして渡しています。
練習問題1.
Go言語を使用してTCPエコーサーバーを作成し、クライアントから受信したメッセージをそのままクライアントに返すプログラムを書いてください。
package main
import (
// 必要なパッケージをインポート
)
func main() {
// TCPサーバーを起動し、クライアントからの接続を待ち受ける
// クライアントからのメッセージを読み込み、同じメッセージをクライアントに返す
}
練習問題2.
Go言語を使用してUDPサーバーとクライアントを作成し、クライアントがサーバーにメッセージを送信し、サーバーがそれを受信してコンソールに表示するプログラムを書いてください。
// UDPサーバープログラム
package main
import (
// 必要なパッケージをインポート
)
func main() {
// UDPサーバーを起動し、メッセージを受信して表示する
}
// UDPクライアントプログラム
package main
import (
// 必要なパッケージをインポート
)
func main() {
// UDPサーバーにメッセージを送信する
}
練習問題3.
Go言語を使用してHTTPクライアントを作成し、特定のURL(例えば http://example.com)からデータを取得し、その内容をコンソールに表示するプログラムを書いてください。
package main
import (
// 必要なパッケージをインポート
)
func main() {
// HTTP GETリクエストを送信し、レスポンスを取得する
// レスポンスボディをコンソールに表示する
}