nsq源码阅读 nsqd源码三 tcp.go

NSQ的TCP逻辑都是这样的,调用internal/protocol/tcp_server.go中的TCPServer:

func TCPServer(listener net.Listener, handler TCPHandler, l app.Logger)
接受客户端连接,在这里客户端为consumer,调用TCPHandler.Handle处理业务逻辑,TCPHandler.Handle是个接口,让不同的业务逻辑自己实现这个接口。

这里在tcp.go文件中实现:

func (p *tcpServer) Handle(clientConn net.Conn) {
	p.ctx.nsqd.logf("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)
	//从流中读取4个字节的数据到buf,被读取的数据,会从流中截取掉
	_, err := io.ReadFull(clientConn, buf)
	if err != nil {
		p.ctx.nsqd.logf("ERROR: failed to read protocol version - %s", err)
		return
	}
	protocolMagic := string(buf)

	p.ctx.nsqd.logf("CLIENT(%s): desired protocol magic '%s'",
		clientConn.RemoteAddr(), protocolMagic)

	var prot protocol.Protocol
	switch protocolMagic {
	case "  V2":
		prot = &protocolV2{ctx: p.ctx}
	default:
		//如果不是"  V2"协议,报错,该goroutine停止
		protocol.SendFramedResponse(clientConn, frameTypeError, []byte("E_BAD_PROTOCOL"))
		clientConn.Close()
		p.ctx.nsqd.logf("ERROR: client(%s) bad protocol magic '%s'",
			clientConn.RemoteAddr(), protocolMagic)
		return
	}

	//接口,实际调用的是protocolV2.IOLoop
	err = prot.IOLoop(clientConn)
	if err != nil {
		p.ctx.nsqd.logf("ERROR: client(%s) - %s", clientConn.RemoteAddr(), err)
		return
	}
}
先判断协议版本,不是“  V2”(前面有两个空格),报错,结束该goroutine。如果是,则调用该协议对应的IOLoop方法,读取协议内容,处理协议的具体行为。这里的prot.IOLoop也是一个接口,供每个协议自己实现,V2的实现方式在protocol_v2.go文件中。

V2协议大致为“  V2 command params\n”或“  V2 command params\r\n”

协议开头必须是“  V2”,command为要执行的命令,命令有IDENTIFY、SUB、PUB等等,params为命令的参数,具体参考官网这里。

Anchor 





你可能感兴趣的:(golang,NSQ源码阅读)