Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 缓冲读取器与listenUDP_Go_Udp_Buffer_Bufferedreader - Fatal编程技术网

Go 缓冲读取器与listenUDP

Go 缓冲读取器与listenUDP,go,udp,buffer,bufferedreader,Go,Udp,Buffer,Bufferedreader,如果我“无限”地使用缓冲读取器等待来自服务器的消息,这与使用ListenUDP不太一样吗 但是如果使用ListenUDP,那么我已经创建了另一个服务器 从这个缓冲读取器中“无限”收集数据是一种不好的做法,还是客户端通常都是这样做的 客户端。转到 package main import ( "fmt" "time" "net" "sync" "bufio" ) func xyz(conn net.Conn, p []byte) { rd := b

如果我“无限”地使用
缓冲读取器
等待来自服务器的消息,这与使用
ListenUDP
不太一样吗

但是如果使用
ListenUDP
,那么我已经创建了另一个服务器

从这个
缓冲读取器中“无限”收集数据是一种不好的做法,还是客户端通常都是这样做的

客户端。转到

package main

import (
    "fmt"
    "time"
    "net"
    "sync"
    "bufio"
)

func xyz(conn net.Conn, p []byte) {
    rd := bufio.NewReader(conn)
    for {
        fmt.Printf("line\n")
        _, err := rd.Read(p)
        if err == nil {
            fmt.Printf("SERVER : %s\n", p)
        } else {
            fmt.Printf("Some error %v\n", err)
        }
    }
}

func main() {
    var wg = &sync.WaitGroup{}
    p :=  make([]byte, 2048)
    conn, err := net.Dial("udp", "127.0.0.1:1234")
    if err != nil {
        fmt.Printf("Some error %v", err)
        return
    }
    wg.Add(1)
    go xyz(conn, p)
    time.Sleep(2 * time.Second);
    fmt.Fprintf(conn, "Give me a hash to work on ...")
    time.Sleep(4 * time.Second)
    wg.Wait()
}
package main

import (
    "fmt"
    "net"
)

func sendResponse(conn *net.UDPConn, addr *net.UDPAddr, hash string) {
    _,err := conn.WriteToUDP([]byte("Hello, here is the hash  - " + hash), addr)
    if err != nil {
        fmt.Printf("Couldn't send response %v", err)
    }
}

func main() {
    hash := "36";
    p := make([]byte, 2048)
    addr := net.UDPAddr{
        Port: 1234,
        IP: net.ParseIP("127.0.0.1"),
    }
    ser, err := net.ListenUDP("udp", &addr)
    if err != nil {
        fmt.Printf("Some error %v\n", err)
        return
    }
    for {
        _, remoteaddr, err := ser.ReadFromUDP(p)
        fmt.Printf("CLIENT : %v : %s\n", remoteaddr, p)
        if err !=  nil {
            fmt.Printf("Some error  %v", err)
            continue
        }
        go sendResponse(ser, remoteaddr, hash)
    }
}
服务器。转到

package main

import (
    "fmt"
    "time"
    "net"
    "sync"
    "bufio"
)

func xyz(conn net.Conn, p []byte) {
    rd := bufio.NewReader(conn)
    for {
        fmt.Printf("line\n")
        _, err := rd.Read(p)
        if err == nil {
            fmt.Printf("SERVER : %s\n", p)
        } else {
            fmt.Printf("Some error %v\n", err)
        }
    }
}

func main() {
    var wg = &sync.WaitGroup{}
    p :=  make([]byte, 2048)
    conn, err := net.Dial("udp", "127.0.0.1:1234")
    if err != nil {
        fmt.Printf("Some error %v", err)
        return
    }
    wg.Add(1)
    go xyz(conn, p)
    time.Sleep(2 * time.Second);
    fmt.Fprintf(conn, "Give me a hash to work on ...")
    time.Sleep(4 * time.Second)
    wg.Wait()
}
package main

import (
    "fmt"
    "net"
)

func sendResponse(conn *net.UDPConn, addr *net.UDPAddr, hash string) {
    _,err := conn.WriteToUDP([]byte("Hello, here is the hash  - " + hash), addr)
    if err != nil {
        fmt.Printf("Couldn't send response %v", err)
    }
}

func main() {
    hash := "36";
    p := make([]byte, 2048)
    addr := net.UDPAddr{
        Port: 1234,
        IP: net.ParseIP("127.0.0.1"),
    }
    ser, err := net.ListenUDP("udp", &addr)
    if err != nil {
        fmt.Printf("Some error %v\n", err)
        return
    }
    for {
        _, remoteaddr, err := ser.ReadFromUDP(p)
        fmt.Printf("CLIENT : %v : %s\n", remoteaddr, p)
        if err !=  nil {
            fmt.Printf("Some error  %v", err)
            continue
        }
        go sendResponse(ser, remoteaddr, hash)
    }
}

您不需要使用
bufio.Reader
来读取
net.Conn
,在UDP连接的情况下,它只会导致问题

UDP不是基于流的,所以您将始终需要读取每个单独的数据报。在最好的情况下,一个
bufio.Reader
只是额外缓冲一次数据,在最坏的情况下,缓冲区几乎满了,您只能得到部分读取,从而丢失数据。一旦缓冲了多个数据报,您也不能再区分消息,除非它们包含额外的帧

只需直接从
net.Conn
读入
[]字节即可:

for {
    n, err := conn.Read(p)
    fmt.Printf("SERVER : %s\n", p[:n])
    if err != nil {
        fmt.Printf("Some error %v\n", err)
        return
    }
}

请使用gofmt!将bufio与UDP连接一起使用通常没有任何意义。UDP基于单个数据报,尝试使用缓冲读取器的目标是什么?bufio.reader不在后台读取,它在调用read时读取,因此即使它工作,它也会毫无理由地添加另一层缓冲。它也没有单个数据报的概念,因此您的
rd.Read
调用可能会返回多个数据报的一部分,尽管不太可能,无法保证bufio.Reader将使用足够的缓冲区空间调用Read以接收整个数据报,并将丢失数据。@MattClendenen:
rd.Read
正在将数据复制到
bufio.Reader
缓冲区,然后再次将其复制到
p
。你也可以跳过它,直接读到
p
。在这里使用bufio是没有帮助的,因为UDP不是基于流的,所以不管发生什么,系统调用的数量都是相同的。不过,额外的缓冲区是一个较小的问题,因为如果缓冲区已满,则部分读取时将丢失数据,并且仍然无法区分缓冲区中已有的数据报。@Mattclenden:a
net.Conn
是一个
io.Reader
,这就是为什么您能够将它用作
bufio.NewReader
的参数。您可以通过调用
Read
等待消息,当
Read
返回时,您可以“执行任务”。