go switch case 匹配不到通过网络接收到的字符串?

代码片段如下:

func dealWithClientMsg(conn net.Conn) {
    read := make([]byte, 2048)
    readTmp := make([]byte, 1024)

    num, err := conn.Read(readTmp)

    if err != nil {
        log.Println("接受客户端消息失败:", err.Error())
    }

    read = append(read, readTmp[:num]...)

    log.Println("接收到客户端消息:", string(read))

    contentList := strings.Split(string(read), ":")
    action := strings.Trim(contentList[0], " ")
    //action := "TUNNELOK"

    fmt.Printf("%s%T",action, action) //此处输出结果:TUNNELOKstring

    switch action {
    case "TUNNELOK":
        fmt.Println("隧道打成功了")
        ......
    }
}

代码中的 action 变量可以确定是 TUNNELOK 了,但是 swich 里面 就是匹配不到,我如果直接将 action 变量的值赋值为 TUNNELOK ,则可以匹配到,实在没法了,遂请问高人这是为何?谢谢指点,小弟感激涕零。

阅读 2.1k
1 个回答

解决方案

action := strings.Trim(contentList[0], " ")

改为

action := strings.TrimSpace(contentList[0])

试一下。

TrimSpace()会 trim 掉所有不可见字符,包括\r\n\t这些。
这是可能的解决方案,再说一下我猜测的原因。

原因推测

你在问题评论里说len(action)的长度是2056,这个2056是怎么来的呢?
大概是TUNNELOK的长度(8)加上了 2048(read := make([]byte, 2048))。

关键在于这几句代码:

read := make([]byte, 2048)
read = append(read, readTmp[:num]...)
contentList := strings.Split(string(read), ":")

首先,make([]byte, 2048)会按照参数里的长度给slice初始化成一个容量和长度都为 2048 的切片,内容是零值
你可以在make下面打印一下read的内容、长度、容量(cap),会发现它的内容是[0 0 0 0 0 0 0 0 ...(省略)],即read内部已经有 2048 个元素了。

紧接着你执行了append,它会把readTmp[:num]...的内容给追加到read的 2048 位之后,所以此时read的长度就是2048 + len(readTmp[:num])了。

然后是第三句,这句其实有两个逻辑:

sRead := string(read)
contentList := strings.Split(sRead, ":")

重点在第一句。
string(read)会直接把[]byte转成string,而此时你的read已经是一个前 2048 位都是 0slice了,这 2048 个 0 也会被转成string,也就是 ASCII 码里为 0 的字符,这是个不可见字符。

这应该就是根本原因了。

根治方法

最上面提供了TrimSpace的解决方案,但这个办法依然会浪费 2048 位空间。
如果要进一步根治的话,也很简单:read不要用make去初始化,改成下面两种就行:

var read []byte
// OR
read := []byte{}

至于readTmp要不要也这么改,你可以自己试一下。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题