post Image
渋川さんの Go ならわかるシステムプログラミングやって見た(1)

渋川さんの書かれている Go ならわかるシステムプログラミングが楽しかったので、自分でも試して見た。
自分へのメモ。

Go 言語はシステムコールとの間に、C, C++ が挟まっていないので、低レベルまで Go で理解できるとのこと。これは楽しい。そして、デバッガを使ってインサイドのコードまで見てシステムコールまで追いかけて解説するというなんとも素晴らしい内容だった。是非本を買いたいところだが、物理本のようなので帰国後買って見る。

デバッガをコンフィグする

この連載はデバッガがポイントなので、用意して見る。私は IntelliJ を使っていないので、Visual Studio Code で同様の設定をする。これはとっても簡単。VS Code から下記の場所からデバッガの設定を作る。

Screen Shot 2017-11-27 at 3.29.12 PM.png

Screen Shot 2017-11-27 at 3.29.34 PM.png

テンプレートができたらそのままでOK.私のは名前だけ変えた。

launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
    {
        "name": "Go Launch file",
        "type": "go",
        "request": "launch",
        "mode": "debug",
        "program": "${file}"
    },
        {
            "name": "Launch",
            "type": "go",
            "request": "launch",
            "mode": "debug",
            "remotePath": "",
            "port": 2345,
            "host": "127.0.0.1",
            "program": "${fileDirname}",
            "env": {},
            "args": [],
            "showLog": true
        }
    ]
}

あとは連載を楽しむのみ

 実際にデバッガを動かして見ると、インターフェイスが変わっているが、重要なことに絞って理解すると、読み替えることができるだろう。基本は変わらない。

この第一回では、ファイルディスクリプタの解説をしている。Go の場合は、(f *File)io.Write(b []byte) (n int, err error) のインターフェイスが同じなら、ポリモルフィズムみたいなことができる。

OS レベルでは、ファイルディスクリプタは、ファイルだけではなく、標準出力、ソケット、乱数、などファイルでないものもファイルと同じように扱えるようになっていますが、これは、Unix 系のOSのお話なので、Windows は異なるとのこと。だから、OSの違いを隠蔽できるように、ファイルディスクリプタを表す構造体を作って、それ経由で操作することで、OSの違いを吸収できるようになっている様子。

Write メソッドは例えば、構造体が、File ではなく、FD (ファイルディスクリプタ) に変わっている。

fd_unix.go

func (fd *FD) Write(p []byte) (int, error) {
    if err := fd.writeLock(); err != nil {
        return 0, err
    }
    defer fd.writeUnlock()
    if err := fd.pd.prepareWrite(fd.isFile); err != nil {
        return 0, err
    }
    var nn int
    for {
        max := len(p)
        if fd.IsStream && max-nn > maxRW {
            max = nn + maxRW
        }
        n, err := syscall.Write(fd.Sysfd, p[nn:max])
        if n > 0 {
            nn += n
        }
        if nn == len(p) {
            return nn, err
        }
        if err == syscall.EAGAIN && fd.pd.pollable() {
            if err = fd.pd.waitWrite(fd.isFile); err == nil {
                continue
            }
        }
        if err != nil {
            return nn, err
        }
        if n == 0 {
            return nn, io.ErrUnexpectedEOF
        }
    }
}

同ファイルの、FD の定義。ファイルディスクリプタは数字のようだが、それ以外にも情報が守るようになっている。

type FD struct {
    // Lock sysfd and serialize access to Read and Write methods.
    fdmu fdMutex

    // System file descriptor. Immutable until Close.
    Sysfd int

    // I/O poller.
    pd pollDesc

    // Writev cache.
    iovecs *[]syscall.Iovec

    // Whether this is a streaming descriptor, as opposed to a
    // packet-based descriptor like a UDP socket. Immutable.
    IsStream bool

    // Whether a zero byte read indicates EOF. This is false for a
    // message based socket connection.
    ZeroReadIsEOF bool

    // Whether this is a file rather than a network socket.
    isFile bool
}
integer value file stream
0 stdin
1 stdout
2 stderr

このあと、今回の記事では、ざまざまな種類の io.Write メソッドを実装していきます。ファイル、http バッファリングするもの、サーバー、gzip 圧縮など、デコレーターパターンを思い出します。バッファを持つものは、Flush() 関数があり、Go は、バッファリングなしでいきなりシステムコールという方式だが、パフォーマンス的に問題ないという感じ。

サンプルプログラム

さて、写経しながら面白く記事を読んだのですが、師匠の教えにしたがって、自分でも簡単な実装を作って見ました。io.Write の実装をして見ました。細かくは説明しませんが、アルファベットの暗号化を行うライターを作って見ましたw

package main

import (
    "fmt"
    "io"
    "os"
)

type asciiEncryptWriter struct {
    w io.Writer
}

func (ew *asciiEncryptWriter) Write(p []byte) (int, error) {
    var b [1]byte
    r := 0
    for n, _ := range p {
        b[0] = p[n]
        if ('a' <= b[0] && b[0] <= 'z') || ('A' <= b[0] && b[0] <= 'Z') {
            if b[0] == 'z' {
                b[0] = 'a'
            }
            if b[0] == 'Z' {
                b[0] = 'A'
            }
            b[0]++
        }
        nw, err := ew.w.Write(b[:])
        if err != nil {
            return nw, err
        }
    }
    return r, nil
}

// NewASCIIEncryptWriter provide  super strong word encryption.
func NewASCIIEncryptWriter(w io.Writer) *asciiEncryptWriter {
    return &asciiEncryptWriter{w}
}

func main() {
    w := NewASCIIEncryptWriter(os.Stdout)
    fmt.Fprintln(w, "Very Strong Encryption")
}

実行

Wfsz Tuspoh Fodszqujpo

こら楽しい連載やわ。プログラミングの楽しさを思い出した。今後の内容もとても楽しみ。


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。