gpt4 book ai didi

sockets - channel 的golang问题(缓冲与非缓冲)

转载 作者:行者123 更新时间:2023-12-01 22:13:54 25 4
gpt4 key购买 nike

我正在一个个人项目上运行,该项目将在连接了一些传感器的Raspberry Pi上运行。

它包含2个程序:

  • 每隔X秒从传感器读取数据的服务器
  • 一个将数据保存在sqlite数据库上并可以发送一些命令的客户端

  • 服务器可以:
  • 从传感器读取数据,将其写入套接字,以便客户端可以将其保存在数据库中
  • 监听套接字,因此当客户端发送一些命令时,它可以执行该命令并将响应发送回客户端

  • 从传感器读取的功能和处理套接字连接的功能在不同的goroutine中执行,因此,为了在从传感器读取数据时在套接字上发送数据,我在主函数中创建了[] byte channel ,将其传递给goroutines。

    当从传感器收集数据(如果连接了客户端)时,会将其写入 channel ,因此另一个函数会将其写入套接字,客户端会接收它。

    我的问题出在这里:如果我连续进行多次写入,则只有第一个数据到达客户端,而其他则没有。但是,如果我在 channel 上编写的函数中放了一点time.sleep,则所有数据都会正确到达客户端。

    无论如何,那是这个小程序的简化版本:
    package main

    import (
    "net"
    "os"
    "sync"
    "time"
    )

    const socketName string = "./test_socket"

    // create to the socket and launch the accept client routine
    func launchServerUDS(ch chan []byte) {
    if err := os.RemoveAll(socketName); err != nil {
    return
    }
    l, err := net.Listen("unix", socketName)
    if err != nil {
    return
    }
    go acceptConnectionRoutine(l, ch)
    }

    // accept incoming connection on the socket and
    // 1) launch the routine to handle commands from the client
    // 2) launch the routine to send data when the server reads from the sensors
    func acceptConnectionRoutine(l net.Listener, ch chan []byte) {
    defer l.Close()
    for {
    conn, err := l.Accept()
    if err != nil {
    return
    }
    go commandsHandlerRoutine(conn, ch)
    go autoSendRoutine(conn, ch)

    }
    }

    // routine that sends data to the client
    func autoSendRoutine(c net.Conn, ch chan []byte) {
    for {
    data := <-ch
    if string(data) == "exit" {
    return
    }
    c.Write(data)
    }
    }

    // handle client connection and calls functions to execute commands
    func commandsHandlerRoutine(c net.Conn, ch chan []byte) {
    for {
    buf := make([]byte, 1024)
    n, err := c.Read(buf)
    if err != nil {
    ch <- []byte("exit")
    break
    }
    // now, for sake of simplicity , only echo commands back to the client
    _, err = c.Write(buf[:n])
    if err != nil {
    ch <- []byte("exit")
    break
    }
    }
    }

    // write on the channel to the autosend routine so the data are written on the socket
    func sendDataToClient(data []byte, ch chan []byte) {
    select {
    case ch <- data:
    // if i put a little sleep here, no problems
    // i i remove the sleep, only data1 is sent to the client
    // time.Sleep(1 * time.Millisecond)
    default:
    }
    }

    func dummyReadDataRoutine(ch chan []byte) {
    for {
    // read data from the sensors every 5 seconds
    time.Sleep(5 * time.Second)
    // read first data and send it
    sendDataToClient([]byte("dummy data1\n"), ch)
    // read second data and send it
    sendDataToClient([]byte("dummy data2\n"), ch)
    // read third data and send it
    sendDataToClient([]byte("dummy data3\n"), ch)
    }
    }

    func main() {
    ch := make(chan []byte)
    wg := sync.WaitGroup{}
    wg.Add(2)
    go dummyReadDataRoutine(ch)
    go launchServerUDS(ch)
    wg.Wait()
    }


    我认为我想念某些东西,不想 sleep ,因为我认为这样做不是正确的方法。是否存在一些错误或更好的方法?与我一样,唯一需要保留的是套接字处理和读取数据功能必须在不同的goroutine中执行。

    最佳答案

    主要问题在于函数:

    func sendDataToClient(data []byte, ch chan []byte) {
    select {
    case ch <- data:
    // if I put a little sleep here, no problems
    // if I remove the sleep, only data1 is sent to the client
    // time.Sleep(1 * time.Millisecond)
    default:
    }

    如果在调用函数时 channel ch尚未准备就绪,则会采用 default大小写,并且永远不会发送 data。在这种情况下,您应该取消该功能并直接发送到 channel 。

    缓冲 channel 与眼前的问题正交,应出于与缓冲IO相似的原因进行缓冲,即为无法立即进行的写操作提供“缓冲”。如果没有缓冲区,代码将无法继续执行,则仅添加一个会延迟可能的死锁。

    您也不需要此处的 exit哨兵值,因为您可以在整个 channel 范围内移动并在完成后将其关闭。但是,这仍然忽略了写错误,但同样需要重新设计。
    for data := range ch {
    c.Write(data)
    }

    您还应该小心地在 channel 上传递 slice ,因为很容易丢失对哪个逻辑进程拥有所有权并将要修改后备阵列的跟踪。我不能从给出的信息中说出通过 channel 传递读写数据是否可以改善体系结构,但这不是大多数go联网代码中都能找到的模式。

    关于sockets - channel 的golang问题(缓冲与非缓冲),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61851783/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com