GO语言的websocket数据解析

最近在学GO语言,需要开发websocket服务器,不想用第三方的websocket服务器框架,准备使用原生TCP硬撸一个websocket服务器。

websocket是基于tcp的协议,对tcp包进行了封装,因此,使用原生tcp服务器,是可以搞定websocket服务器的。

websocket最关键的三个步骤:首次websocket握手、将tcp客户端发来的数据解析成websocket数据、将数据加密成webscoket数据发送给tcp客户端。

 

websocket 握手:

func (this *SocketServer) Handle(conn net.Conn,buf []byte){
   strbuf := string(buf)
   websocket := dbDriver.RegFind(strbuf,"^GET[\\w\\W]+?Sec-WebSocket-Key: ([\\w\\W]+==)")
   if len(websocket)==2 {
      secWebsocketKey  := websocket[1]
      guid := "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
      // 计算Sec-WebSocket-Accept
      h := sha1.New()
      io.WriteString(h, secWebsocketKey + guid)
      accept := make([]byte, 28)
      fmt.Println(string(accept))
      base64.StdEncoding.Encode(accept, h.Sum(nil))
      response := "HTTP/1.1 101 Switching Protocols\r\n"
      response = response + "Sec-WebSocket-Accept: " + string(accept) + "\r\n"
      response = response + "Connection: Upgrade\r\n"
      response = response + "Upgrade: websocket\r\n\r\n"
      conn.Write([]byte(response))
      

   }else{
      //不是websocket
   }
}

将tcp客户端发来的数据按照websocket格式解析:

func WebSocketParse(data []byte)(string){
   en_bytes := []byte("")
   cn_bytes := make([]int,0)

   v:= data[1] & 0x7f
   p:=0
   res:=""
   switch v {
   case 0x7e:
      p =4
   case 0x7f:
      p = 10
   default:
      p = 2
   }
   mask := data[p:p+4]
   data_tmp := data[p+4:]
   nv :=""
   nv_bytes :=[]byte("")
   nv_len :=0

   for k,v := range(data_tmp){

      nv = string(int(v ^ mask[k%4]))
      nv_bytes = []byte(nv)
      nv_len = len(nv_bytes)
      if nv_len == 1 {
         en_bytes=BytesCombine(en_bytes,nv_bytes)
      }else{
         en_bytes=BytesCombine(en_bytes,[]byte("%s"))
         cn_bytes = append(cn_bytes,int(v ^ mask[k%4]))
      }
   }

   //处理中文
   cn_str := make([]interface{},0)
   if len(cn_bytes) >2 {

      clen := len(cn_bytes)
      count := int(clen/3)

      for i:=0;i<count;i++ {
         mm := i*3

         hh := make([]byte,3)
         h1 ,_ := IntToBytes(cn_bytes[mm],1)
         h2 ,_ := IntToBytes(cn_bytes[mm+1],1)
         h3 ,_ := IntToBytes(cn_bytes[mm+2],1)
         hh[0]=h1[0]
         hh[1]=h2[0]
         hh[2]=h3[0]

         cn_str = append(cn_str, string(hh))
      }

      new := string(bytes.Replace(en_bytes,[]byte("%s%s%s"),[]byte("%s"),-1))
      res = fmt.Sprintf(new,cn_str...)

   }else{
      res = string(en_bytes)
   }
   return res
}

将要发送的数据加密成websocket格式

func BytesCombine(pBytes ...[]byte) []byte {
   return bytes.Join(pBytes, []byte(""))
}
func WebSocketSend(data []byte)([]byte){
   lenth := len(data)
   token := string(0x81)
   if lenth<126 {
      token+= string(lenth)
   }
   bb,_ := IntToBytes(0x81,1)
   b0 := bb[0]
   b1 := byte(0)
   framePos :=0

   fmt.Println("长度",lenth)
   switch {
   case lenth >= 65536:
      writeBuf :=make([]byte,10)
      writeBuf[framePos] = b0
      writeBuf[framePos+1] = b1 | 127
      binary.BigEndian.PutUint64(writeBuf[framePos+2:], uint64(lenth))

      return BytesCombine(writeBuf,data)
   case lenth > 125:
      fmt.Println("》125")
      writeBuf :=make([]byte,4)
      writeBuf[framePos] = b0
      writeBuf[framePos+1] = b1 | 126
      binary.BigEndian.PutUint16(writeBuf[framePos+2:], uint16(lenth))
      fmt.Println(writeBuf)
      return BytesCombine(writeBuf,data)
   default:
      writeBuf :=make([]byte,2)
      writeBuf[framePos] = b0
      writeBuf[framePos+1] = b1 | byte(lenth)

      return BytesCombine(writeBuf,data)
   }


有了上面三个函数,随便写一个TCP服务器,然后使用上述三个函数去和tcp客户端通信,就是websocket服务器了。

 

实测效果:

效果一级棒。。。。图就不贴了。。。。

题外话。。。

其实POST、GET、websocket、tcp都是tcp协议,在Python上,我曾经编写一个服务器程序,可以同时支持POST、GET、websocket、tcp四种tcp客户端,实用性大大增加

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值