panjf2000 / gnet

🚀 gnet is a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go.

Home Page:https://gnet.host

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

chen2ding opened this issue · comments

Actions I've taken before I'm here

  • I've thoroughly read the documentations about this problem but still have no answer.
  • I've searched the Github Issues/Discussions but didn't find any similar problems that have been solved.
  • I've searched the internet for this problem but didn't find anything helpful.

Questions with details

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

Code snippets (optional)

No response

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
}

🤖 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
}

@panjf2000 请问这是什么问题呢

🤖 Non-English text detected, translating...


@panjf2000 What is the problem?

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

🤖 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.

First format your code, it's unreadable.

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

🤖 Non-English text detected, translating...


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

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.

🤖 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
}

🤖 Non-English text detected, translating...


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

Oh, I understand