NSQ 源码分析之NSQD--TCPServer

14 篇文章 0 订阅

今天来说说NSQD中的TCP 服务,TCP服务的任务包括接收/处理/响应发布、消费、延时、消费确认等命令。

详细流程参考 https://blog.csdn.net/H_L_S/article/details/104709619 中的逻辑流程图。

主要代码文件:

1.internal/protocol/tcp_server.go,该文件主要是启动一个服务监听,循环接收客户端连接,并且将conn,交由一个goroutine ,执行指定Handle 。

func TCPServer(listener net.Listener, handler TCPHandler, logf lg.AppLogFunc) error {
	var wg sync.WaitGroup
    ...
	for {
        //接收新连接
		clientConn, err := listener.Accept()
        ....
		wg.Add(1)
        //启动goroutin 处理clientConn
		go func() {
			handler.Handle(clientConn)
			wg.Done()
		}()
	}
	wg.Wait()
	return nil
}

2.nsqd/tcp.go,该文件主要处理conn的连接。Handle函数主要两件事,一是协议版本验证,二是如果协议没有问题,启动IOLoop,处理客户端请求,比如发布,消费,消费确认等。

type tcpServer struct {
	ctx   *context //NSQD 实例
	conns sync.Map //并发安全的MAP
}

func (p *tcpServer) Handle(clientConn net.Conn) {
	buf := make([]byte, 4)
	_, err := io.ReadFull(clientConn, buf) //版本为4个字节
	....
	protocolMagic := string(buf)
    ....
	var prot protocol.Protocol
	switch protocolMagic { //验证版本协议
	case "  V2":
		prot = &protocolV2{ctx: p.ctx}
	default: //版本协议错误,返回错误,关闭连接
		protocol.SendFramedResponse(clientConn, frameTypeError, []byte("E_BAD_PROTOCOL"))
		clientConn.Close()
	
		return
	}
    //记录正在处理IP
	p.conns.Store(clientConn.RemoteAddr(), clientConn)

	//循环处理客户端请求,包括订阅,发布,消费确认等命令。
	err = prot.IOLoop(clientConn)
	if err != nil {
		p.ctx.nsqd.logf(LOG_ERROR, "client(%s) - %s", clientConn.RemoteAddr(), err)
	}
    //处理结束,请求IP 记录
	p.conns.Delete(clientConn.RemoteAddr())
}

3.internal/protocol/protocol.go, 该文件主要是定义了IOLoop的接口,同时提供了二个回复客户端消息的函数。

type Protocol interface {
	IOLoop(conn net.Conn) error
}

//发送的消息的格式:len(4个字节)+body(消息体)
func SendResponse(w io.Writer, data []byte) (int, error) {
	err := binary.Write(w, binary.BigEndian, int32(len(data)))
	if err != nil {
		return 0, err
	}

	n, err := w.Write(data)
	if err != nil {
		return 0, err
	}
	return (n + 4), nil
}
//发送带有frameType(可以认为是消息类型,包括错误响应,正常消息响应等)
//格式:len(4字节)+frameType(4个字节)+body(消息体)
func SendFramedResponse(w io.Writer, frameType int32, data []byte) (int, error) {
	beBuf := make([]byte, 4)
	size := uint32(len(data)) + 4

	binary.BigEndian.PutUint32(beBuf, size)
	n, err := w.Write(beBuf)
	if err != nil {
		return n, err
	}

	binary.BigEndian.PutUint32(beBuf, uint32(frameType))
	n, err = w.Write(beBuf)
	if err != nil {
		return n + 4, err
	}

	n, err = w.Write(data)
	return n + 8, err
}

4.nsqd/protocol_v2.go是IOLoop,的具体实现。负责接收请求,处理请求,topic/channel的主要处理逻辑都在这实现,是整个tcpServer 的核心。 因为比较复杂,会在下一篇分析。

总结

1.internal/protocol/tcp_server.go 主要是用于接收客户的连接请求,同时将conn交于指定的Handle处理。

2.nsqd/tcp.go 实现tcp_server.go中的Handle,主要是验证协议版本,同时启动IOLoop 处理请求。

3.internal/protocol/protocol.go  定义了IOLoop 接口 和 实现了两个回复客户端消息的函数。

4.nsqd/protocol_v2.go 是IOLoop的具体实现,主要负责接收请求,处理请求,响应客户端。

 

下次分享:nsqd 中 TCPServer 的IOLoop的具体实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值