nsq 源码阅读(三) nsqlookupd tcp handler 处理函数

3. nsqlookupd 源码阅读(2) tcp handler 处理函数

每个nsqd 生产者的状态发生变化时,都会通知nsqlookup将自己从nsqlookup的DB中删除。


func (p *tcpServer) Handle(clientConn net.Conn) {
    p.ctx.nsqlookupd.logf(LOG_INFO, "TCP: new client(%s)", clientConn.RemoteAddr())

    // The client should initialize itself by sending a 4 byte sequence indicating
    // the version of the protocol that it intends to communicate, this will allow us
    // to gracefully upgrade the protocol away from text/line oriented to whatever...
    buf := make([]byte, 4)
    _, err := io.ReadFull(clientConn, buf)
    if err != nil {
        p.ctx.nsqlookupd.logf(LOG_ERROR, "failed to read protocol version - %s", err)
        return
    }
    // protocolMagic 默认是  "  V1"
    protocolMagic := string(buf)
    p.ctx.nsqlookupd.logf(LOG_INFO, "CLIENT(%s): desired protocol magic '%s'",
        clientConn.RemoteAddr(), protocolMagic)

    var prot protocol.Protocol
    switch protocolMagic {
    case "  V1":
        prot = &LookupProtocolV1{ctx: p.ctx}
    default:
        protocol.SendResponse(clientConn, []byte("E_BAD_PROTOCOL"))
        clientConn.Close()
        p.ctx.nsqlookupd.logf(LOG_ERROR, "client(%s) bad protocol magic '%s'",
            clientConn.RemoteAddr(), protocolMagic)
        return
    }
    // 循环读取消息
    err = prot.IOLoop(clientConn)
    if err != nil {
        p.ctx.nsqlookupd.logf(LOG_ERROR, "client(%s) - %s", clientConn.RemoteAddr(), err)
        return
    }
}

目前的 protocolMagic 只支持 V1 ,所以客户端在连接的时候,服务端首先要验证conn发过来的protocolMagic 是不是v1 是的话,new一个Protocol ,调用其IOLoop 循环读取方法。

func (p *LookupProtocolV1) IOLoop(conn net.Conn) error {
    var err error
    var line string

    client := NewClientV1(conn)
    reader := bufio.NewReader(client)
    for {
        line, err = reader.ReadString('\n')
        if err != nil {
            break
        }
        line = strings.TrimSpace(line)
        params := strings.Split(line, " ")
        fmt.Println("params", params)
        var response []byte
        response, err = p.Exec(client, reader, params)
        if err != nil {
            ctx := ""
            if parentErr := err.(protocol.ChildErr).Parent(); parentErr != nil {
                ctx = " - " + parentErr.Error()
            }
            p.ctx.nsqlookupd.logf(LOG_ERROR, "[%s] - %s%s", client, err, ctx)

            _, sendErr := protocol.SendResponse(client, []byte(err.Error()))
            if sendErr != nil {
                p.ctx.nsqlookupd.logf(LOG_ERROR, "[%s] - %s%s", client, sendErr, ctx)
                break
            }

            // errors of type FatalClientErr should forceably close the connection
            if _, ok := err.(*protocol.FatalClientErr); ok {
                break
            }
            continue
        }

        if response != nil {
            _, err = protocol.SendResponse(client, response)
            if err != nil {
                break
            }
        }
    }

    conn.Close()
    p.ctx.nsqlookupd.logf(LOG_INFO, "CLIENT(%s): closing", client)
    if client.peerInfo != nil {
        registrations := p.ctx.nsqlookupd.DB.LookupRegistrations(client.peerInfo.id)
        for _, r := range registrations {
            if removed, _ := p.ctx.nsqlookupd.DB.RemoveProducer(r, client.peerInfo.id); removed {
                p.ctx.nsqlookupd.logf(LOG_INFO, "DB: client(%s) UNREGISTER category:%s key:%s subkey:%s",
                    client, r.Category, r.Key, r.SubKey)
            }
        }
    }
    return err
}

IOLoop 方法会不停的读取客户端的数据信息,并且默认有以下四种类型。

类型 功能 备注
PING nsqd 客户端通知nsqlookup 自己还活着
IDENTIFY nsqd客户端首次连接nsqlookupd的时候,首先进行鉴定,以及记录这个生产者
REGISTER 新的topic 或者channel创建的时候,通知nsqlookupd 进行注册
UNREGISTER 删除时,通知注销

客户端nsqd链接的时候首先发送一个IDENTIFY 消息类型,进行鉴定,鉴定通过后会将nsqd存在topic信息等进

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值