// 发送心跳包 func ping(conn *net.TCPConn) { ticker := time.NewTicker(60 * time.Second) for _ = range ticker.C { //write writePingMsg := &pb.PbClientPing{ Ping: proto.Bool(true), Timestamp: proto.Int64(time.Now().Unix()), } err := handlers.SendPbData(conn, packet.PK_ClientPing, writePingMsg) if err != nil { return } fmt.Println(conn.RemoteAddr().String(), "ping.") } }
// 处理收发数据包 func handlePackets(uuid int, conn *net.TCPConn, receivePackets <-chan *packet.Packet, chStop <-chan bool) { defer func() { if e := recover(); e != nil { log.Printf("Panic: %v\r\n") } }() for { select { case <-chStop: return // 消息包处理 case p := <-receivePackets: if p.Type == packet.PK_ServerAcceptLogin { // 登陆回复 // read readMsg := &pb.PbServerAcceptLogin{} packet.Unpack(p, readMsg) if readMsg.GetLogin() == true { log.Printf("[%v]: [%v]---[%v]\r\n", getUuid(uuid), readMsg.GetTipsMsg(), convert.TimestampToTimeString(readMsg.GetTimestamp())) } // write,随机向10个人发送消息 for i := 0; i < 10; i++ { rand.Seed(time.Now().UnixNano()) to_uuid := rand.Intn(total) + 1 // [1, total] if to_uuid == uuid { continue } writeMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(getUuid(uuid)), ToUuid: proto.String(getUuid(to_uuid)), TextMsg: proto.String(strings.Repeat("hello,世界!!!", 100)), Timestamp: proto.Int64(time.Now().Unix()), } handlers.SendPbData(conn, packet.PK_C2CTextChat, writeMsg) } } else if p.Type == packet.PK_C2CTextChat { // 普通消息 // read readMsg := &pb.PbC2CTextChat{} packet.Unpack(p, readMsg) from_uuid := readMsg.GetFromUuid() to_uuid := readMsg.GetToUuid() txt_msg := readMsg.GetTextMsg() timestamp := readMsg.GetTimestamp() if to_uuid != getUuid(uuid) { log.Printf("[%v]收到[%v]发来的不属于自己的包,该包应该属于[%v]\r\n", getUuid(uuid), from_uuid, to_uuid) } else { log.Printf("[%v]:[%v]收到来自[%v]的消息: [%v]", convert.TimestampToTimeString(timestamp), getUuid(uuid), from_uuid, txt_msg) // write, 回复时在原基础上加点消息,控制长度范围 var to_txt_msg string var add_txt string = " 你好 hello world" if len(txt_msg)+len(add_txt) <= 2048 { to_txt_msg = txt_msg + add_txt } else { to_txt_msg = txt_msg } writeMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(getUuid(uuid)), ToUuid: proto.String(from_uuid), TextMsg: proto.String(to_txt_msg), Timestamp: proto.Int64(time.Now().Unix()), } handlers.SendPbData(conn, packet.PK_C2CTextChat, writeMsg) } } else { log.Printf("[%v]收到未知包\r\n", getUuid(uuid)) } } } }
// 模拟客户端(uuid) func testClient(uuid int) { defer func() { if e := recover(); e != nil { log.Printf("uuid: [%v] Panic: %v\r\n", getUuid(uuid), e) } }() // 连接服务器 tcpAddr, _ := net.ResolveTCPAddr("tcp4", config.Addr) conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { log.Printf("[%v] DialTCP失败: %v\r\n", getUuid(uuid), err) return } // 发送登陆请求 writeLoginMsg := &pb.PbClientLogin{ Uuid: proto.String(getUuid(uuid)), Version: proto.Float32(3.14), Timestamp: proto.Int64(time.Now().Unix()), } err = handlers.SendPbData(conn, packet.PK_ClientLogin, writeLoginMsg) if err != nil { log.Printf("[%v] 发送登陆包失败: %v\r\n", getUuid(uuid), err) return } // 下面这些处理和server.go中的一样 receivePackets := make(chan *packet.Packet, 20) // 接收到的包 chStop := make(chan bool) // 通知停止消息处理 request := make([]byte, 1024) rbuf := ringbuffer.NewRingBuffer(1024) defer func() { conn.Close() chStop <- true }() // 发送心跳包 go ping(conn) // 处理接受到的包 go handlePackets(uuid, conn, receivePackets, chStop) for { readSize, err := conn.Read(request) if err != nil { return } if readSize > 0 { rbuf.Write(request[:readSize]) // 包长(4) + 类型(4) + 包体(len([]byte)) for { if rbuf.Size() >= 8 { pacLen := convert.BytesToUint32(rbuf.Bytes(4)) if rbuf.Size() >= int(pacLen) { rbuf.Peek(4) receivePackets <- &packet.Packet{ Len: pacLen, Type: convert.BytesToUint32(rbuf.Read(4)), Data: rbuf.Read(int(pacLen) - 8), } } else { break } } else { break } } } } }
func testBB(i_uuid string) { tcpAddr, _ := net.ResolveTCPAddr("tcp4", config.Addr) conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { log.Printf("%v DialTCP失败: %v\r\n", i_uuid, err) return } defer conn.Close() // 登陆 // write writeLoginMsg := &pb.PbClientLogin{ Uuid: proto.String(i_uuid), Version: proto.Float32(3.14), Timestamp: proto.Int64(time.Now().Unix()), } err = handlers.SendPbData(conn, packet.PK_ClientLogin, writeLoginMsg) if err != nil { log.Printf("%v 发送登陆包失败: %v\r\n", i_uuid, err) return } var ( bLen []byte = make([]byte, 4) bType []byte = make([]byte, 4) pacLen uint32 ) // read if n, err := io.ReadFull(conn, bLen); err != nil && n != 4 { log.Printf("Read pacLen failed: %v\r\n", err) return } if n, err := io.ReadFull(conn, bType); err != nil && n != 4 { log.Printf("Read pacType failed: %v\r\n", err) return } if pacLen = convert.BytesToUint32(bLen); pacLen > uint32(2048) { log.Printf("pacLen larger than maxPacLen\r\n") return } pacData := make([]byte, pacLen-8) if n, err := io.ReadFull(conn, pacData); err != nil && n != int(pacLen) { log.Printf("Read pacData failed: %v\r\n", err) return } pac := &packet.Packet{ Len: pacLen, Type: convert.BytesToUint32(bType), Data: pacData, } readAccepLoginMsg := &pb.PbServerAcceptLogin{} err = packet.Unpack(pac, readAccepLoginMsg) if err != nil { log.Printf("%v Unpack error: %v\r\n", i_uuid, err) return } fmt.Println(readAccepLoginMsg.GetLogin()) fmt.Println(readAccepLoginMsg.GetTipsMsg()) fmt.Println(convert.TimestampToTimeString(readAccepLoginMsg.GetTimestamp())) // 定时发送心跳包 go ping(conn) // 先向对方发送消息 // write go func() { writeC2CMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(i_uuid), ToUuid: proto.String(u_uuid), TextMsg: proto.String("hi, 我的uuid是: " + i_uuid), Timestamp: proto.Int64(time.Now().Unix()), } err := handlers.SendPbData(conn, packet.PK_C2CTextChat, writeC2CMsg) if err != nil { log.Printf("%v 发送消息失败: %v\r\n", i_uuid, err) return } }() // 死循环,接收消息和发送消息 for { fmt.Println("坐等消息到来...") // read if n, err := io.ReadFull(conn, bLen); err != nil && n != 4 { log.Printf("Read pacLen failed: %v\r\n", err) return } if n, err := io.ReadFull(conn, bType); err != nil && n != 4 { log.Printf("Read pacType failed: %v\r\n", err) return } if pacLen = convert.BytesToUint32(bLen); pacLen > uint32(2048) { log.Printf("pacLen larger than maxPacLen\r\n") return } pacData := make([]byte, pacLen-8) if n, err := io.ReadFull(conn, pacData); err != nil && n != int(pacLen) { log.Printf("Read pacData failed: %v\r\n", err) return } pac := &packet.Packet{ Len: pacLen, Type: convert.BytesToUint32(bType), Data: pacData, } readC2CMsg := &pb.PbC2CTextChat{} err = packet.Unpack(pac, readC2CMsg) if err != nil { log.Printf("%v 读取到的消息Unpack error: %v\r\n", i_uuid, err) return } from_uuid := readC2CMsg.GetFromUuid() to_uuid := readC2CMsg.GetToUuid() txt_msg := readC2CMsg.GetTextMsg() timestamp := readC2CMsg.GetTimestamp() fmt.Println("from_uuid:", from_uuid) fmt.Println("to_uuid:", to_uuid) fmt.Println("txt_msg:", txt_msg) fmt.Println("timestamp:", convert.TimestampToTimeString(timestamp)) time.Sleep(5 * time.Second) // write writeC2CMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(to_uuid), ToUuid: proto.String(from_uuid), TextMsg: proto.String(txt_msg + "我是 " + i_uuid), Timestamp: proto.Int64(timestamp), } err = handlers.SendPbData(conn, packet.PK_C2CTextChat, writeC2CMsg) if err != nil { log.Printf("%v 回复消息失败: %v\r\n", i_uuid, err) return } } }
// 模拟客户端(uuid) func testClient(uuid int) { defer func() { if e := recover(); e != nil { log.Printf("uuid: [%v] Panic: %v\r\n", getUuid(uuid), e) } }() // 连接服务器 tcpAddr, _ := net.ResolveTCPAddr("tcp4", config.Addr) conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { log.Printf("[%v] DialTCP失败: %v\r\n", getUuid(uuid), err) return } // 发送登陆请求 writeLoginMsg := &pb.PbClientLogin{ Uuid: proto.String(getUuid(uuid)), Version: proto.Float32(3.14), Timestamp: proto.Int64(time.Now().Unix()), } err = handlers.SendPbData(conn, packet.PK_ClientLogin, writeLoginMsg) if err != nil { log.Printf("[%v] 发送登陆包失败: %v\r\n", getUuid(uuid), err) return } // 下面这些处理和server.go中的一样 receivePackets := make(chan *packet.Packet, 100) // 接收到的包 chStop := make(chan bool) // 通知停止消息处理 defer func() { conn.Close() chStop <- true }() // 发送心跳包 go ping(conn) // 处理接受到的包 go handlePackets(uuid, conn, receivePackets, chStop) // 包长(4) + 类型(4) + 包体(len(pacData)) var ( bLen []byte = make([]byte, 4) bType []byte = make([]byte, 4) pacLen uint32 ) for { if n, err := io.ReadFull(conn, bLen); err != nil && n != 4 { log.Printf("Read pacLen failed: %v\r\n", err) return } if n, err := io.ReadFull(conn, bType); err != nil && n != 4 { log.Printf("Read pacType failed: %v\r\n", err) return } if pacLen = convert.BytesToUint32(bLen); pacLen > uint32(2048) { log.Printf("pacLen larger than maxPacLen\r\n") return } pacData := make([]byte, pacLen-8) if n, err := io.ReadFull(conn, pacData); err != nil && n != int(pacLen) { log.Printf("Read pacData failed: %v\r\n", err) return } receivePackets <- &packet.Packet{ Len: pacLen, Type: convert.BytesToUint32(bType), Data: pacData, } } }
func testBB(i_uuid string) { tcpAddr, _ := net.ResolveTCPAddr("tcp4", config.Addr) conn, err := net.DialTCP("tcp", nil, tcpAddr) if err != nil { log.Printf("%v DialTCP失败: %v\r\n", i_uuid, err) return } defer conn.Close() // 登陆 // write writeLoginMsg := &pb.PbClientLogin{ Uuid: proto.String(i_uuid), Version: proto.Float32(3.14), Timestamp: proto.Int64(time.Now().Unix()), } err = handlers.SendPbData(conn, packet.PK_ClientLogin, writeLoginMsg) if err != nil { log.Printf("%v 发送登陆包失败: %v\r\n", i_uuid, err) return } // read buf := make([]byte, 1024) n, err := conn.Read(buf) if err != nil { log.Printf("%v 登陆回应包读取失败: %v\r\n", i_uuid, err) return } pac := getPacFromBuf(buf, n) readAccepLoginMsg := &pb.PbServerAcceptLogin{} err = packet.Unpack(pac, readAccepLoginMsg) if err != nil { log.Printf("%v Unpack error: %v\r\n", i_uuid, err) return } fmt.Println(readAccepLoginMsg.GetLogin()) fmt.Println(readAccepLoginMsg.GetTipsMsg()) fmt.Println(convert.TimestampToTimeString(readAccepLoginMsg.GetTimestamp())) // 定时发送心跳包 go ping(conn) // 先向对方发送消息 // write go func() { writeC2CMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(i_uuid), ToUuid: proto.String(u_uuid), TextMsg: proto.String("hi, 我的uuid是: " + i_uuid), Timestamp: proto.Int64(time.Now().Unix()), } err := handlers.SendPbData(conn, packet.PK_C2CTextChat, writeC2CMsg) if err != nil { log.Printf("%v 发送消息失败: %v\r\n", i_uuid, err) return } }() // 死循环,接收消息和发送消息 recBuf := make([]byte, 1024) for { fmt.Println("坐等消息到来...") // read n, err := conn.Read(recBuf) if err != nil { log.Printf("%v 读取消息失败: %v\r\n", i_uuid, err) return } fmt.Println("消息读取完毕") pac := getPacFromBuf(recBuf, n) readC2CMsg := &pb.PbC2CTextChat{} err = packet.Unpack(pac, readC2CMsg) if err != nil { log.Printf("%v 读取到的消息Unpack error: %v\r\n", i_uuid, err) return } from_uuid := readC2CMsg.GetFromUuid() to_uuid := readC2CMsg.GetToUuid() txt_msg := readC2CMsg.GetTextMsg() timestamp := readC2CMsg.GetTimestamp() fmt.Println("from_uuid:", from_uuid) fmt.Println("to_uuid:", to_uuid) fmt.Println("txt_msg:", txt_msg) fmt.Println("timestamp:", convert.TimestampToTimeString(timestamp)) time.Sleep(5 * time.Second) // write writeC2CMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(to_uuid), ToUuid: proto.String(from_uuid), TextMsg: proto.String(txt_msg + "我是 " + i_uuid), Timestamp: proto.Int64(timestamp), } err = handlers.SendPbData(conn, packet.PK_C2CTextChat, writeC2CMsg) if err != nil { log.Printf("%v 回复消息失败: %v\r\n", i_uuid, err) return } } }