以下の内容はhttps://devlights.hatenablog.com/entry/2025/04/08/073000より取得しました。


Goメモ-560 (UNIXドメインソケットの抽象名前空間)(netパッケージのUnixConn版)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。

UNIXドメインソケットにはLinux版のみの機能として「抽象名前空間」(Abstract Namespace)という概念があります。

通常、UNIXドメインソケットを利用する場合は実体となるファイルが必要となりますが、抽象名前空間を用いる場合はファイルを作成する必要はありません。

以下の特徴を持ちます。

  • ソケットのアドレス(名前)の先頭にNULバイト(\0)を付ける
  • ファイルシステム上にソケットファイルを作成しない
  • プロセス終了時に自動的にクリーンアップされる

知ってると結構便利な概念ですので、ついでなのでGoでサンプル作ってみました。syscallパッケージを使って低レイヤーな処理で扱うこともできますし、netパッケージからでも利用できます。

今回は net パッケージの UnixConn を利用した版。

サンプル

main.go

package main

import (
    "bytes"
    "errors"
    "flag"
    "io"
    "log"
    "net"
    "os"
    "os/signal"
    "syscall"
)

type (
    Args struct {
        IsServer bool
    }
)

const (
    // 抽象名前空間のソケットアドレス(@記号で始まる名前は\0に変換される)
    serverAddr = "@go_unix_domain_socket_test"
    bufSize    = len("hello")
)

var (
    args Args
)

func init() {
    flag.BoolVar(&args.IsServer, "server", false, "server mode")
}

func main() {
    log.SetFlags(log.Lmicroseconds)
    flag.Parse()

    if err := run(); err != nil {
        panic(err)
    }
}

func run() error {
    var err error
    switch args.IsServer {
    case true:
        err = runServer()
    default:
        err = runClient()
    }

    if err != nil {
        return err
    }

    return nil
}

func runServer() error {
    addr, err := net.ResolveUnixAddr("unix", serverAddr)
    if err != nil {
        return err
    }

    ln, err := net.ListenUnix("unix", addr)
    if err != nil {
        return err
    }
    defer ln.Close()

    sigCh := make(chan os.Signal, 1)
    signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
    go func(sigCh <-chan os.Signal) {
        <-sigCh
        ln.Close()
        os.Exit(0)
    }(sigCh)

    conn, err := ln.AcceptUnix()
    if err != nil {
        return err
    }
    defer conn.Close()

    buf := make([]byte, bufSize)
    for {
        clear(buf)

        n, err := conn.Read(buf)
        if n == 0 || errors.Is(err, io.EOF) {
            log.Println("[S] disconnect")
            break
        }

        if err != nil {
            if errors.Is(err, syscall.EINTR) {
                continue
            }
            return err
        }

        message := buf[:n]
        log.Printf("[S] Recv (%s)", message)

        message = bytes.ToUpper(buf[:n])
        _, err = conn.Write(message)
        if err != nil {
            return err
        }
        log.Printf("[S] Send (%s)", message)
    }

    return nil
}

func runClient() error {
    addr, err := net.ResolveUnixAddr("unix", serverAddr)
    if err != nil {
        return err
    }

    conn, err := net.DialUnix("unix", nil, addr)
    if err != nil {
        return err
    }
    defer conn.Close()

    buf := make([]byte, bufSize)
    copy(buf, []byte("hello"))

    _, err = conn.Write(buf)
    if err != nil {
        return err
    }
    log.Printf("[C] Send (%s)", buf)

    clear(buf)
    n, err := conn.Read(buf)
    if err != nil {
        if errors.Is(err, syscall.EINTR) {
            return nil
        }
        return err
    }

    if n == 0 {
        log.Println("[C] disconnect")
        return nil
    }

    message := string(buf[:n])
    log.Printf("[C] Recv (%s)", message)

    return nil
}

Taskfile.yml

# https://taskfile.dev

version: '3'

vars:
  APP_NAME: app

tasks:
  default:
    cmds:
      - task: build
      - task: run
  build:
    cmds:
      - go build -o {{.APP_NAME}} main.go
  run:
    cmds:
      - ./{{.APP_NAME}} -server &
      - sleep 1
      - ./{{.APP_NAME}}
      - pkill -f './{{.APP_NAME}} -server' || true
  clean:
    cmds:
      - rm -f ./{{.APP_NAME}}

実行

$ task
task: [build] go build -o app main.go
task: [run] ./app -server &
task: [run] sleep 1
task: [run] ./app
09:01:13.238544 [C] Send (hello)
09:01:13.239925 [S] Recv (hello)
09:01:13.240143 [S] Send (HELLO)
09:01:13.240205 [C] Recv (HELLO)
09:01:13.240314 [S] disconnect
task: [run] pkill -f './app -server' || true

参考情報

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。




以上の内容はhttps://devlights.hatenablog.com/entry/2025/04/08/073000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14