Go somehow blocks execution and does not exit the program

Asked 1 years ago, Updated 1 years ago, 59 views

Go writes a TCP server that sends four values of investment (start, high, low, closing, and time) to the client.
The first 8 bytes of data to send are the number of bytes in a four-valued structure represented by JSON followed by the actual JSON string.

I wrote a program like the one below to test this TCP server, but the client blocked Read for some reason (maybe there's something else on the server...) and it doesn't end well.
Why?
The following test program's Candle is a struct with 4 values.
The server side code is also listed below it.

The environment is x64 Linux, Go1.18


import(
    "fmt"
    "log"
    "net"
    "strconv"
    "string"
    "sync"
    "time"
)

typeCandle structure {
    Count int `json: "Count, omitempty"`
    Open float64`json: "Open"`
    Close float64`json: "Close"`
    Low float64`json: "Low"`
    High float64`json: "High"`
    Datetime time.Time`json: "Datetime"`
}

funcmain(){
    data_buf:=make([]byte, 1024*1024)
    server_addr:="localhost"
    port —=33333
    port_str:="33333"
    JST: = time.FixedZone ("JST", 9*60*60)
    cs: = make ([]Candle, 0,200)
    newline_sep: = strings.Split(data_csv, "\n") // data_csv is the csv string of the value of the Candle
    for_,v:=range newline_sep{
        varc Candle
        comma_sep: = strings.Split(v, ", ")
        date_str: =comma_sep[0]+"+comma_sep[1]
        date,err: = time.ParseInLocation("January 2, 2006 15:04", date_str, JST)
        if err!=nil{
            log.Fatal(err)
        }
        c. Datetime=date
        open,err: = strconv.ParseFloat(comma_sep[2],64)
        if err!=nil{
            log.Fatal(err)
        }
        high,err —= strconv.ParseFloat (comma_sep[3],64)
        if err!=nil{
            log.Fatal(err)
        }
        low,err —= strconv.ParseFloat (comma_sep[4],64)
        if err!=nil{
            log.Fatal(err)
        }
        clo,err —= strconv.ParseFloat (comma_sep[5],64)
        if err!=nil{
            log.Fatal(err)
        }
        c. Open=open
        c. Close=clo
        c. High = high
        c. Low = low
        cs = append(cs,c)
    } // Create an array of Candles to be sent to the server so far
    num_candle: =len(cs)
    fmt.Println("num_candle", num_candle)
    handle_chan:=make(chanCandle)

    go func(server_chanCandle) {//Launching the server in a different routine, the server receives the Candle from server_chan and sends it to the client
        s: = NewCandleServer(server_chan)
        s.Run(server_addr, port)
    }(candle_chan)
    wg:=&sync.WaitGroup{}
    wg.Add(1)
    go func(){
        time.Sleep (1500*time.Millisecond)
        for_,v:=rangecs{
            handle_chanlen(data_buf){
            data_buf=make([]byte,size)
        }
        fmt.Println("read hang before")
        _,err=conn.Read(data_buf)
        fmt.Println("read hang")
        if err!=nil{
            log.Fatal("payload read error:", error)
        }
        i+=1
    }
    wg.Wait()
    if i!=num_candle{
        _= fmt.Errorf("something Error")
    }
}


import(
    "encoding/json"
    "fmt"
    "investment/calc"
    "investment/kabucom3"
    "log"
    "net"
    "strconv"
    "sync"
)

typeServiceable interface {
    kabucom3.PositionsSuccess | calc.Candle
}

funcByteLength(b[]byte)([]byte, int){
    buff:=make([]byte,8)
    b_len —=len(b)
    b_len64 —=uint64(b_len)
    for i —=0; i<8;i++{
        buff[i]=byte((b_len64>>((7-i)*8))&byte(0xff)
    }
    buff=append(buff,b...)
    return buff, b_len
}

typeCandleServer [T Serviceable] structure {
    Conns* sync.Map
    Cchan T
}

func(t*CandleServer[T])Run(addr string, port int){
    prefer func(){
        t.Conns.Range(func(k,vany)bool{
            c: = k. (*net.Conn)
            (*c).Close()
            return true
        })
    }()
    go func(){
        variable = 0
        for {
            select{
            casev:=<-t.C:
                c+ = 1
                fmt.Println("candle_server", "case", c)
                b,err —=json.Marshal(v)
                if err!=nil{
                    fmt.Println("hang",err)
                }
                result_buff,_ —=ByteLength(b)
                t.Conns.Range(func(k,vany)bool{
                    c: = k. (*net.Conn)
                    _,err: =(*c).Write(result_buff)
                    if err!=nil{
                        (*c).Close()
                        t.Conns.Delete(k)
                    }
                    return true
                })
                fmt.Println("candle_server", "after range")
            }
        }
    }()
    ln,err: = net.Listen("tcp", addr+":"+strconv.Itoa(port))
    if err!=nil{
        log.Fatal("Listen Error", error)
    }
    for {
        conn,err —=ln.Accept()
        if err!=nil{
            log.Fatal("Accept Error", error)
        }
        t.Conns.Store(&conn, structure{}{})
    }

}

func NewCandleServer [T Serviceable] (cchan T)*CandleServer [T]{
    return&CandleServer[T]{C:c,Conns:&sync.Map{}}
}

go tcp

2022-09-30 18:03

1 Answers

The io.Reader Read(buff) method is blocked until the buffer size has been received.
If the sender sends less than that, the Read will never complete.

A streaming decoder is standard for receiving JSON decode results.

var result map [string] interface {}
iferr:=json.NewDecorder(conn).Decode(&result);err!=nil{
  error handling
}

Read the stream until it can be interpreted as JSON.


2022-09-30 18:03

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.