Home >Backend Development >Golang >How to Achieve Bidirectional Communication with Unix Sockets in Go?

How to Achieve Bidirectional Communication with Unix Sockets in Go?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-12-02 01:25:11975browse

How to Achieve Bidirectional Communication with Unix Sockets in Go?

Bidirectional Unix Sockets in Go

When implementing Unix sockets in Go, it's essential to establish a bidirectional communication channel to enable both the client and server to send and receive data. This article explores a fundamental issue encountered when using Unix sockets: unidirectional connections leading to data transmission in only one direction.

Understanding the Problem

In the provided code example, the server can receive data from the client but fails to respond with data. This issue stems from the fact that the c.Read() call in the client code is never followed up by a c.Write() call. As a result, the client fails to read the server's response, creating the illusion of a unidirectional connection.

Resolving the Issue

To establish bidirectional communication, we need to modify both the client and server code.

Server Modification

The modified server code introduces a defer statement to handle closing the connection gracefully in case of an error. Additionally, we utilize break to exit the reader goroutine when necessary.

package main

import (
    "log"
    "net"
)

func echoServer(c net.Conn) {
    defer c.Close()

    for {
        buf := make([]byte, 512)
        nr, err := c.Read(buf)
        if err != nil {
            return
        }

        data := buf[0:nr]
        println("Server got:", string(data))
        _, err = c.Write(data)
        if err != nil {
            log.Fatal("Write: ", err)
        }
    }
}

func main() {
    l, err := net.Listen("unix", "/tmp/echo.sock")
    if err != nil {
        log.Fatal("listen error:", err)
    }

    for {
        fd, err := l.Accept()
        if err != nil {
            log.Fatal("accept error:", err)
        }

        go echoServer(fd)
    }
}

Client Modification

The modified client code adds a reader goroutine to continuously read incoming data from the server. The defer statement ensures the connection is closed upon termination of the main function.

package main

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

func reader(r io.Reader) {
    defer r.(net.Conn).Close()  // Ensure connection is closed even on panic

    buf := make([]byte, 1024)
    for {
        n, err := r.Read(buf[:])
        if err != nil {
            return
        }
        println("Client got:", string(buf[0:n]))
    }
}

func main() {
    c, err := net.Dial("unix", "/tmp/echo.sock")
    if err != nil {
        log.Fatal(err)
    }

    go reader(c)

    for {
        _, err := c.Write([]byte("hi"))
        if err != nil {
            log.Fatal(err)
            break
        }
        time.Sleep(1e9)
    }
}

With these modifications, the client-server communication becomes bidirectional, allowing both parties to send and receive data seamlessly.

The above is the detailed content of How to Achieve Bidirectional Communication with Unix Sockets in Go?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn