zha*_*zhi 4 io buffer byte tcp go
我在执行tcp c / s演示时遇到问题,发现在服务器端使用io.ReadFull(conn,aByteArr)或bytes.Buffer.ReadFrom(conn)时,这很奇怪,服务器似乎不会直到客户端退出,换句话说,服务器卡住,才读取连接中的数据,但是我可以使用基本的conn.Read(aBuffer)读取数据。为什么这两种方法如此奇怪?
因为我希望服务器处理任意大小的数据,所以我不喜欢使用基本方式,我的意思是conn.Read(),它必须首先创建具有指定大小的字节片。请帮我。
我可以提供我的代码:客户:
package main
import (
"net"
"fmt"
"bufio"
"time"
"runtime"
)
func send(s string, ch chan string){
conn, err := net.Dial("tcp", ":4000")
if err != nil {
fmt.Println(err)
}
fmt.Fprintf(conn, s)
fmt.Println("send: ", s)
/*
s := "server run"
conn.Write([]byte(s))
*/
status, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
fmt.Println("error: ", err)
}
ch <- status
}
func main(){
runtime.GOMAXPROCS(runtime.NumCPU())
fmt.Println("cpu: ", runtime.NumCPU())
ch := make(chan string, 5)
timeout := time.After(10 * time.Second)
i := 0
for{
go send(fmt.Sprintf("%s%d", "client", i), ch)
i++
select {
case ret := <-ch:
fmt.Println(ret)
case <-timeout:
fmt.Println("time out")
return
}
}
}
Run Code Online (Sandbox Code Playgroud)
服务器:
package main
import (
"net"
"log"
"io"
"fmt"
"time"
//"bytes"
)
func main(){
// Listen on TCP port 2000 on all interfaces.
l, err := net.Listen("tcp", ":4000")
if err != nil {
log.Fatal(err)
}
defer l.Close()
for {
// Wait for a connection.
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
// Handle the connection in a new goroutine.
// The loop then returns to accepting, so that
// multiple connections may be served concurrently.
go func(c net.Conn) {
fmt.Println(c.RemoteAddr())
defer c.Close()
// Echo all incoming data.
/* basic
buf := make([]byte, 100)
c.Read(buf)
fmt.Println(string(buf))
//io.Copy(c, c)
c.Write(buf)
// Shut down the connection.
*/
/* use a ReadFrom
var b bytes.Buffer
b.ReadFrom(conn)
fmt.Println("length: ", b.Len())
c.Write(b.Bytes())
*/
// use io.ReadAll
byteArr := make([]byte, 100)
n, err := io.ReadFull(c, byteArr)
if err != nil {
fmt.Println(err)
}
fmt.Println(n, byteArr[:n], time.Now())
n, _ = c.Write(byteArr[:n])
fmt.Println("write: ", n, time.Now())
}(conn)
}
}
Run Code Online (Sandbox Code Playgroud)
首先:您永远不会在客户端中关闭已建立的连接。在每次调用send时,您都会建立一个新的conn,但切勿刷新或关闭该连接。这似乎很奇怪,并且可能是这里唯一的问题(例如,如果某个层将您的内容缓冲到关闭或刷新)。
看来您认为应该有一种简便的方法来“读取”某个连接或io.Reader。没有。如果您对此感到不满,则不应该如此。您想读取“任意大小的数据”,但任意大小可能意味着418 Peta字节。这很多,可能需要一些时间。我敢打赌,您没有计算能力来处理此类数据大小。读取任意大小基本上需要以块的形式读取它,并以块的形式对其进行处理,因为您无法处理418个Peta字节。
io.Reader提供块读取功能。笨拙的 这就是许多协议始于数据大小的原因:您读取了6个字节(如“ 1423”),解析了整数并知道消息长度为1432个字节。从那里,你可以使用提供了方便的功能bufio.Scanner,bytes.Buffer,io.ReadFull和等。甚至那些要求EOFs并可能失败。
如果您的消息不是以某些长度指示(或固定长度:-)开头,则必须阅读直到EOF。为此EOF,您必须关闭发送方,否则连接仍处于打开状态,并可能决定将来某个时候发送更多的东西。