panjf2000 / gnet

🚀 gnet is a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go.
https://gnet.host
Apache License 2.0
9.7k stars 1.04k forks source link

[Question]: Is the netpoll v1 version defaulting to horizontal triggering, and the V2 version defaulting to edge triggering? #575

Closed chen2ding closed 7 months ago

chen2ding commented 7 months ago

Actions I've taken before I'm here

Questions with details

netpoll v1版本默认是水平触发,V2版本默认是边缘触发吗?

Code snippets (optional)

No response

panjf2000 commented 7 months ago

See #573

chen2ding commented 7 months ago
func (uc *UlebCodec) ReadULEB128(conn gnet.Conn) ([]byte, error) {
    bodyLen := 0
    ulebLen := 1
    for {
        if ulebLen > 5 {
            break
        }
        buf, err := conn.Peek(ulebLen)
        // 连接中没有数据
        if err != nil || len(buf) != ulebLen {
            return nil, nil
        }
        v := 0
        cc := 0
        for _, b := range buf {
            v += (int(b) & 0x7F) << cc
            cc += 7
            if b&0x80 == 0 {
                bodyLen = v
                break
            }
        }
        // uleb 读取完整退出循环
        if bodyLen > 0 {
            break
        }
        ulebLen++
    }
    defer conn.Discard(bodyLen + ulebLen)
    //等待读取bodyLen
    if bodyLen > uc.readBuffSize {
        return nil, fmt.Errorf("abnormal msg bodyLen:%d > readBuffSize:%d", bodyLen, uc.readBuffSize)
    }
    buf, _ := conn.Peek(ulebLen + bodyLen)
    //PrintHex(buf[ulebLen:])
    return buf[ulebLen:], nil
} 

同样的代码,v1升级V2后不能正常工作,上面是V2代码,下面v1

func (uc *UlebCodec) ReadULEB128(conn gnet.Conn) ([]byte, error) {
    bodyLen := 0
    ulebLen := 1
    for {
        if ulebLen > 5 {
            break
        }
        n, buf := conn.ReadN(ulebLen)
        // 连接中没有数据
        if n == 0 || n != ulebLen {
            return nil, nil
        }
        v := 0
        cc := 0
        for _, b := range buf {
            v += (int(b) & 0x7F) << cc
            cc += 7
            if b&0x80 == 0 {
                bodyLen = v
                break
            }
        }
        // uleb 读取完整退出循环
        if bodyLen > 0 {
            break
        }
        ulebLen++
    }
    defer conn.ShiftN(bodyLen + ulebLen)
    //等待读取bodyLen
    if bodyLen > uc.readBuffSize {
        return nil, fmt.Errorf("abnormal msg bodyLen:%d > readBuffSize:%d", bodyLen, uc.readBuffSize)
    }
    _, buf := conn.ReadN(ulebLen + bodyLen)
    return buf[ulebLen:], nil
}
gh-translator commented 7 months ago

🤖 Non-English text detected, translating...


func (uc *UlebCodec) ReadULEB128(conn gnet.Conn) ([]byte, error) { bodyLen := 0 ulebLen := 1 for { ifulebLen > 5 { break } buf, err := conn.Peek(ulebLen) // There is no data in the connection if err != nil || len(buf) != ulebLen { return nil, nil } v := 0 cc := 0 for , b := range buf { v += (int(b) & 0x7F) << cc cc += 7 if b&0x80 == 0 { bodyLen = v break } } // uleb reads completely and exits the loop if bodyLen > 0 { break } ulebLen++ } defer conn.Discard(bodyLen + ulebLen) //Waiting to read bodyLen if bodyLen > uc.readBuffSize { return nil, fmt.Errorf("abnormal msg bodyLen:%d > readBuffSize:%d", bodyLen, uc.readBuffSize) } buf, := conn.Peek(ulebLen + bodyLen) //PrintHex(buf[ulebLen:]) return buf[ulebLen:], nil } The same code, v1 cannot work properly after upgrading to V2. The above is the V2 code, and the following v1

func (uc *UlebCodec) ReadULEB128(conn gnet.Conn) ([]byte, error) {
bodyLen := 0
ulebLen := 1
for {
ifulebLen > 5 {
break
}
n, buf := conn.ReadN(ulebLen)
// There is no data in the connection
if n == 0 || n != ulebLen {
return nil, nil
}
v := 0
cc := 0
for _, b := range buf {
v += (int(b) & 0x7F) << cc
cc += 7
if b&0x80 == 0 {
bodyLen = v
break
}
}
// uleb reads completely and exits the loop
if bodyLen > 0 {
break
}
ulebLen++
}
defer conn.ShiftN(bodyLen + ulebLen)
//Waiting to read bodyLen
if bodyLen > uc.readBuffSize {
return nil, fmt.Errorf("abnormal msg bodyLen:%d > readBuffSize:%d", bodyLen, uc.readBuffSize)
}
_, buf := conn.ReadN(ulebLen + bodyLen)
return buf[ulebLen:], nil
}
chen2ding commented 7 months ago

@panjf2000 请问这是什么问题呢

gh-translator commented 7 months ago

🤖 Non-English text detected, translating...


@panjf2000 What is the problem?

chen2ding commented 7 months ago

@panjf2000 调试感觉是buf中的数据我没有读完,然后后面就不触发OnTraffic了,v1版本正常的

gh-translator commented 7 months ago

🤖 Non-English text detected, translating...


@panjf2000 The debugging feeling is that I haven’t finished reading the data in buf, and then OnTraffic will not be triggered later. The v1 version is normal.

panjf2000 commented 7 months ago

First format your code, it's unreadable.

chen2ding commented 7 months ago

@panjf2000 已经格式化了,麻烦看下上面代码呢

gh-translator commented 7 months ago

🤖 Non-English text detected, translating...


@panjf2000 It has been formatted. Please take a look at the above code.

panjf2000 commented 7 months ago

One of the best practices with gnet v2 is to keep reading and decoding packets until you reach an incomplete packet, otherwise the OnTraffic won't be invoked again until there is new arrival of data on the socket. I think the root cause of your issue here is that gnet v1 would loop reading and decoding packets internally while gnet v2 wouldn't.

gh-translator commented 7 months ago

🤖 Non-English text detected, translating...


One of the best practices with v2 gnet is to continue reading and decoding packets until an incomplete packet arrives, otherwise not calling OnTraffic again until new data arrives on the socket. I think the root cause of your problem is that gnetv1 internally loops reading and decoding packets, while gnetv2 does not.

I can confirm that the v1 version is not reading in the inner loop, the decode code is above This is the V1 outer code

func (s *Server) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
msg := BinaryJson.DecodeGJson(frame)
if msg == nil {
action = gnet.Close
return
}
client, ok := c.Context().(*Client)
if !ok || client == nil {
return
}
task := func() {
msgType, _ := msg.GetInt("t")
switch msgType {
case rpc.PingMsg:
if err := s.Codec.WriteULEB128(client.Conn, rpc.NewPingResp()); err != nil {
client.Close()
}
client.UpdateLastPingTime()
case rpc.PongMsg:
case rpc.ReqMsg, rpc.PushMsg:
req := &rpc.Req{}
req.FromGJson(msg)
if req.Param == nil {
return
}
resp := s.Handler.HandleReq(client, req)
// Requests that do not require a reply will not be processed if the response is obtained.
if resp == nil {
return
}
// Determine whether it is an error response message
if _, ok := msg.GetString("e"); ok {
client.Close() // Wrong response information, actively close the connection
return
}
if _, ok := msg.GetString("ec"); ok {
client.Close() // Wrong response information, actively close the connection
return
}
if err := s.Codec.WriteULEB128(client.Conn, resp); err != nil {
client.Close()
}
case rpc.RespMsg:
resp := &rpc.Resp{}
resp.FromGJson(msg)
s.Handler.HandleResp(client, resp)
default:
xlog.Ins.Error(s.Handler.Name(), zap.Error(fmt.Errorf("Unknown message type: %d", msgType)))
}
}
_ = s.pool.Submit(task)
return
}
panjf2000 commented 7 months ago

https://github.com/panjf2000/gnet/blob/1.x/eventloop_unix.go#L125-L126

chen2ding commented 7 months ago

https://github.com/panjf2000/gnet/blob/1.x/eventloop_unix.go#L125-L126

哦哦,了解

gh-translator commented 7 months ago

🤖 Non-English text detected, translating...


https://github.com/panjf2000/gnet/blob/1.x/eventloop_unix.go#L125-L126

Oh, I understand