go语言nsq源码解读六 tcp.go、tcp_server.go

本篇讲nsqlookupd中tcp.go、tcp_server.go

tcp_server.go位于util目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package util
       
import  (
     "log"
     "net"
     "runtime"
     "strings"
)

type TCPHandler interface  {
    Handle (net. Conn )
}

/**
*本方法开始接受客户端连接,并注册处理方法
*/

func TCPServer (listener net. Listener , handler TCPHandler )  {
     log. Printf ( "TCP: listening on %s" , listener. Addr ( ). String ( ) )

     for  {
        clientConn , err  := listener. Accept ( )
         if err  != nil  {
             if nerr , ok  := err. (net. Error ) ; ok  && nerr. Temporary ( )  {
                 log. Printf ( "NOTICE: temporary Accept() failure - %s" , err. Error ( ) )
                runtime. Gosched ( )
                 continue
             }
             // theres no direct way to detect this error because it is not exposed
             if  !strings. Contains (err. Error ( ) ,  "use of closed network connection" )  {
                 log. Printf ( "ERROR: listener.Accept() - %s" , err. Error ( ) )
             }
             break
         }
         //handler由调用时通过参数传入,作为工具方法,将可能的变化放在外部,以保证本方法可以有尽可能多的适用范围
        go handler. Handle (clientConn )
     }

     log. Printf ( "TCP: closing %s" , listener. Addr ( ). String ( ) )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package nsqlookupd

import  (
     "io"
     "log"
     "net"

     "github.com/bitly/nsq/util"
)

type tcpServer  struct  {
    context  *Context
}

//
// nsqlookupd接收到tcp数据时,会调用本方法处理。
//实现了/util/tcp_server.go中定义的TCPHandler接口
//

func  (*tcpServer ) Handle (clientConn net. Conn )  {
     log. Printf ( "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...
     //客户端在初始化自己的时候,需要发送4字节的数据用来标识它自己所有使用协议版本。将来升级协议的时候可以避免使用旧协议的客户端不能使用。
    buf  := make ( [ ]byte ,  4 )
    _ , err  := io. ReadFull (clientConn , buf )
     if err  != nil  {
         log. Printf ( "ERROR: failed to read protocol version - %s" , err. Error ( ) )
         return
     }
     //获取协议内容
    protocolMagic  := string (buf )

     log. Printf ( "CLIENT(%s): desired protocol magic '%s'" , clientConn. RemoteAddr ( ) , protocolMagic )

     //util\Protocol.go中定义了一个Protocol的接口
    var prot util. Protocol

     switch protocolMagic  {
     case  "  V1" :
         //当前只支持"  V1"协议(前两有两个空格,所以总共是4字节),协议在nsqlookupd\lookup_protocol_v1.go文件中定义,这里创建了LookupProtocolV1的实例
         //LookupProtocolV1实现了Protocol接口
        prot  =  &LookupProtocolV1 {context : p. context }
     default :
         //如果不是"  V1"协议,则协议出错,断开链接,返回。
        util. SendResponse (clientConn ,  [ ]byte ( "E_BAD_PROTOCOL" ) )
        clientConn. Close ( )
         log. Printf ( "ERROR: client(%s) bad protocol magic '%s'" , clientConn. RemoteAddr ( ) , protocolMagic )
         return
     }

     //如果是"  V1"f协议,这里就进入了LookupProtocolV1的IOLoop方法。此方法里有for死循环运行,直到出现error时,才会执行下面的代码。
    err  = prot. IOLoop (clientConn )
     if err  != nil  {
         log. Printf ( "ERROR: client(%s) - %s" , clientConn. RemoteAddr ( ) , err. Error ( ) )
         return
     }
}

从以上代码可看出,tcp.go和tcp_server.go主要功能就是监听并接受TCP请求,收到请求后,将数据转给lookup_protocol_v1.go来处理。这个下篇再讲。

转载于:https://www.cnblogs.com/zhangboyu/p/7456973.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值