go-signal - 解答

サーバー実装

// cmd/server/main.go
package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

var (
    currentByte byte
    bitCount    int
    message     []byte
)

func main() {
    fmt.Printf("Server PID: %d\n", os.Getpid())

    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, syscall.SIGUSR1, syscall.SIGUSR2)

    for sig := range sigChan {
        handleSignal(sig)
    }
}

func handleSignal(sig os.Signal) {
    // ビットを設定
    if sig == syscall.SIGUSR2 {
        currentByte |= (1 << (7 - bitCount))
    }
    bitCount++

    // 8ビット揃った
    if bitCount == 8 {
        if currentByte == 0 {
            // 終端文字
            fmt.Println(string(message))
            message = nil
        } else {
            message = append(message, currentByte)
        }
        currentByte = 0
        bitCount = 0
    }
}

クライアント実装

// cmd/client/main.go
package main

import (
    "fmt"
    "os"
    "strconv"
    "syscall"
    "time"
)

func main() {
    if len(os.Args) < 3 {
        fmt.Println("Usage: client <pid> <message>")
        os.Exit(1)
    }

    pid, err := strconv.Atoi(os.Args[1])
    if err != nil {
        fmt.Println("Invalid PID")
        os.Exit(1)
    }

    message := os.Args[2]

    for _, char := range message {
        sendByte(pid, byte(char))
    }
    sendByte(pid, 0) // 終端
}

func sendByte(pid int, b byte) {
    for i := 7; i >= 0; i-- {
        var sig syscall.Signal
        if (b>>i)&1 == 1 {
            sig = syscall.SIGUSR2
        } else {
            sig = syscall.SIGUSR1
        }

        syscall.Kill(pid, sig)
        time.Sleep(100 * time.Microsecond)
    }
}