// 客户端(群主)申请解散讨论组 func HandleClientDisbandGroup(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientDisbandGroup{} packet.Unpack(recPacket, readMsg) from_id := readMsg.GetFromUuid() group_id := readMsg.GetGroupId() // timestamp := readMsg.GetTimestamp() // 验证from_id确实是该conn,并且是group_id的群主 group_name, group_owner := groupinfo.GetGroupNameAndOwner(group_id) if from_id != ConnMapUuid.Get(conn).(string) || group_owner != from_id { CloseConn(conn) return } // 解散讨论组 ret := groupinfo.DisbandGroup(from_id, group_id) tips_msg := "解散讨论组[" + group_name + "]成功" if ret { tips_msg = "解散讨论组[" + group_name + "]失败" } // write writeMsg := &pb.PbServerNotifyDisbandGroup{ Disband: proto.Bool(ret), GroupId: proto.String(group_id), GroupName: proto.String(group_name), TipsMsg: proto.String(tips_msg), Timestamp: proto.Int64(time.Now().Unix()), } SendPbData(conn, packet.PK_ServerNotifyDisbandGroup, writeMsg) }
// 客户端申请加入讨论组 func HandleClientJoinGroup(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientJoinGroup{} packet.Unpack(recPacket, readMsg) from_uuid := readMsg.GetFromUuid() group_id := readMsg.GetGroupId() // note_msg := readMsg.GetNoteMsg() // timestamp := readMsg.GetTimestamp() // 加入讨论组 if ret := groupinfo.JoinGroup(from_uuid, group_id); !ret { return } group_name, _ := groupinfo.GetGroupNameAndOwner(group_id) // write writeMsg := pb.PbServerNotifyJoinGroup{ ApplicantUuid: proto.String(from_uuid), GroupId: proto.String(group_id), GroupName: proto.String(group_name), Timestamp: proto.Int64(time.Now().Unix()), } // 通知所有组员,这个消息不离线存储 group_members := groupinfo.GetAllUuid(group_id) for i := 1; i < len(group_members); i++ { SendPbData(UuidMapConn.Get(group_members[i]).(*net.TCPConn), packet.PK_ServerNotifyJoinGroup, writeMsg) } }
// 客户端申请建立讨论组 func HandleClientBuildGroup(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientBuildGroup{} packet.Unpack(recPacket, readMsg) uuid := ConnMapUuid.Get(conn).(string) group_name := readMsg.GetGroupName() // 建立讨论组 ret, group_id := groupinfo.BuildGroup(group_name, uuid) tips_msg := "讨论组[" + group_name + "]建立成功" if ret { tips_msg = "讨论组[" + group_name + "]建立失败" } // write writeMsg := &pb.PbServerNotifyBuildGroup{ Build: proto.Bool(ret), GroupId: proto.String(group_id), GroupName: proto.String(group_name), OwnerUuid: proto.String(uuid), TipsMsg: proto.String(tips_msg), Timestamp: proto.Int64(time.Now().Unix()), } SendPbData(conn, packet.PK_ServerNotifyBuildGroup, writeMsg) }
// 客户端请求获取讨论组信息 func HandleClientRequestGroupInfo(conn *net.TCPConn, recPacket *packet.Packet) { readMsg := &pb.PbClientRequestGroupInfo{} packet.Unpack(recPacket, readMsg) uuid := readMsg.GetFromUuid() // timestamp := readMsg.GetTimestamp() groupids := groupinfo.GetAllGroup(uuid) var allGroupInfo []*pb.PbGroupInfo for _, group_id := range groupids { s := groupinfo.GetAllUuid(group_id) group_name, owner_uuid, member_uuid := s[0], s[1], s[2:] gi := &pb.PbGroupInfo{ GroupId: proto.String(group_id), GroupName: proto.String(group_name), OwnerUuid: proto.String(owner_uuid), MemberUuid: member_uuid, } allGroupInfo = append(allGroupInfo, gi) } // write writeMsg := &pb.PbServerResponseGroupInfo{ FromUuid: proto.String(uuid), AllGroupInfo: allGroupInfo, Timestamp: proto.Int64(time.Now().Unix()), } SendPbData(conn, packet.PK_ServerResponseGroupInfo, writeMsg) }
// 客户端登陆 func HandleClientLogin(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientLogin{} packet.Unpack(recPacket, readMsg) uuid := readMsg.GetUuid() // 检测uuid合法性 if cid.UuidCheckExist(uuid) { // 如果已经在线则关闭以前的conn if cid.UuidCheckOnline(uuid) { co := UuidMapConn.Get(uuid) if co != nil { CloseConn(co.(*net.TCPConn)) } } // 上线conn InitConn(conn, uuid) } else { CloseConn(conn) } // fmt.Println("uuid:", readMsg.GetUuid()) // fmt.Println("version:", readMsg.GetVersion()) // fmt.Println("timestamp:", convert.TimestampToTimeString(readMsg.GetTimestamp())) // write writeMsg := &pb.PbServerAcceptLogin{ Login: proto.Bool(true), TipsMsg: proto.String("登陆成功"), Timestamp: proto.Int64(time.Now().Unix()), } SendPbData(conn, packet.PK_ServerAcceptLogin, writeMsg) }
// 处理心跳 func HandleClientPing(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientPing{} packet.Unpack(recPacket, readMsg) // fmt.Println("ping:", readMsg.GetPing()) // fmt.Println("timestamp:", convert.TimestampToTimeString(readMsg.GetTimestamp())) }
// 客户端下线 func HandleClientLogout(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientLogout{} packet.Unpack(recPacket, readMsg) // fmt.Println("logout:", readMsg.GetLogout()) // fmt.Println("timestamp:", convert.TimestampToTimeString(readMsg.GetTimestamp())) CloseConn(conn) }
// 处理讨论组消息转发 func HandleGroupTextChat(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbGroupTextChat{} packet.Unpack(recPacket, readMsg) from_uuid := ConnMapUuid.Get(conn).(string) group_id := readMsg.GetGroupId() txt_msg := readMsg.GetTextMsg() // timestamp := readMsg.GetTimestamp() // 验证发送者,这样会影响性能,视情况可以把这个验证去掉 if readMsg.GetFromUuid() != from_uuid || !groupinfo.ExistUuidFromGroup(group_id, from_uuid) { CloseConn(conn) return } // write writeMsg := &pb.PbGroupTextChat{ FromUuid: proto.String(from_uuid), GroupId: proto.String(group_id), TextMsg: proto.String(txt_msg), Timestamp: proto.Int64(time.Now().Unix()), } // 在线消息包 pac1, err := packet.Pack(packet.PK_GroupTextChat, writeMsg) if err != nil { log.Printf("%v\r\n", err) return } // 离线消息包 pac2, err := packet.Pack(packet.PK_ServerResponseGroupOfflineMsg, writeMsg) if err != nil { log.Printf("%v\r\n", err) return } // 将消息转发给所有组员(除了自己),不在线则离线存储 group_members := groupinfo.GetAllUuid(group_id) for i := 1; i < len(group_members); i++ { if group_members[i] == from_uuid { continue } if cid.UuidCheckOnline(group_members[i]) { to_conn := UuidMapConn.Get(group_members[i]).(*net.TCPConn) SendByteStream(to_conn, pac1.GetBytes()) } else { groupmsg.AddMsg(group_members[i], string(pac2.GetBytes())) } } }
// 处理C2C消息转发 func HandleC2CTextChat(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbC2CTextChat{} packet.Unpack(recPacket, readMsg) from_uuid := ConnMapUuid.Get(conn).(string) to_uuid := readMsg.GetToUuid() txt_msg := readMsg.GetTextMsg() // timestamp := readMsg.GetTimestamp() // 验证发送者的真实性以及发送对象是否存,若消息伪造,则断开该连接 if readMsg.GetFromUuid() != from_uuid || !cid.UuidCheckExist(to_uuid) { CloseConn(conn) return } // write writeMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(from_uuid), ToUuid: proto.String(to_uuid), TextMsg: proto.String(txt_msg), Timestamp: proto.Int64(time.Now().Unix()), } // 在线消息包 pac1, err := packet.Pack(packet.PK_C2CTextChat, writeMsg) if err != nil { log.Printf("%v\r\n", err) return } // 离线消息包 pac2, err := packet.Pack(packet.PK_ServerResponseC2COfflineMsg, writeMsg) if err != nil { log.Printf("%v\r\n", err) return } // 若 to_uuid 在线,则转发该消息,发送失败 或者 to_uuid不在线 则保存为离线消息 if cid.UuidCheckOnline(to_uuid) { to_conn := UuidMapConn.Get(to_uuid).(*net.TCPConn) if SendByteStream(to_conn, pac1.GetBytes()) != nil { c2cmsg.AddMsg(to_uuid, string(pac2.GetBytes())) report.AddCount(report.OfflineMsg, 1) } else { report.AddCount(report.OnlineMsg, 1) } } else { c2cmsg.AddMsg(to_uuid, string(pac2.GetBytes())) report.AddCount(report.OfflineMsg, 1) } }
// 处理登陆 func HandleClientLogin(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientLogin{} packet.Unpack(recPacket, readMsg) uuid := readMsg.GetUuid() // 检测uuid合法性 if cid.UuidCheckExist(uuid) { // 如果已经在线则关闭以前的conn if cid.UuidCheckOnline(uuid) { co := UuidMapConn.Get(uuid) if co != nil { CloseConn(co.(*net.TCPConn)) } } // 上线conn InitConn(conn, uuid) } else { CloseConn(conn) } // fmt.Println("uuid:", readMsg.GetUuid()) // fmt.Println("version:", readMsg.GetVersion()) // fmt.Println("timestamp:", convert.TimestampToTimeString(readMsg.GetTimestamp())) // write writeMsg := &pb.PbServerAcceptLogin{ Login: proto.Bool(true), TipsMsg: proto.String("登陆成功"), Timestamp: proto.Int64(time.Now().Unix()), } SendPbData(conn, packet.PK_ServerAcceptLogin, writeMsg) // 检查是否有该uuid的离线消息存在,若有,则发送其离线消息 if offmsgNum := c2c.GetMsgNum(uuid); offmsgNum > 0 { // 这里比较复杂,后续再优化(可以多个离线消息一起发送) // 得到所有离线消息 // fmt.Println("转发离线消息") msgs := c2c.GetMsgs(uuid, offmsgNum) c2c.DeleteMsgs(uuid, offmsgNum, offmsgNum) for i, _ := range msgs { SendByteStream(conn, []byte(msgs[i])) } } }
// 客户端请求C2C离线消息 func HandleClientRequestC2COfflineMsg(conn *net.TCPConn, recPacket *packet.Packet) { readMsg := &pb.PbClientRequestC2COfflineMsg{} packet.Unpack(recPacket, readMsg) uuid := readMsg.GetFromUuid() // 检查是否有该uuid的离线消息存在,若有,则发送其离线消息 if offmsgNum := c2cmsg.GetMsgNum(uuid); offmsgNum > 0 { // 这里比较复杂,后续再优化(可以多个离线消息一起发送) // 暂时将所有离线消息单独发送 msgs := c2cmsg.GetMsgs(uuid, offmsgNum) c2cmsg.DeleteMsgs(uuid, offmsgNum, offmsgNum) for i, _ := range msgs { SendByteStream(conn, []byte(msgs[i])) } } }
// 处理客户端之间的消息转发 func HandleC2CTextChat(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbC2CTextChat{} packet.Unpack(recPacket, readMsg) from_uuid := ConnMapUuid.Get(conn).(string) to_uuid := readMsg.GetToUuid() txt_msg := readMsg.GetTextMsg() timestamp := readMsg.GetTimestamp() // 验证发送者的真实性以及发送对象是否存,若消息伪造,则断开该连接 if readMsg.GetFromUuid() != from_uuid || !dao.UuidCheckExist(to_uuid) { CloseConn(conn) return } // write writeMsg := &pb.PbC2CTextChat{ FromUuid: proto.String(from_uuid), ToUuid: proto.String(to_uuid), TextMsg: proto.String(txt_msg), Timestamp: proto.Int64(timestamp), } pac, err := packet.Pack(packet.PK_C2CTextChat, writeMsg) if err != nil { log.Printf("%v\r\n", err) return } // 若 to_uuid 在线,则转发该消息,发送失败 或者 to_uuid不在线 则保存为离线消息 if dao.UuidCheckOnline(to_uuid) { // fmt.Println("在线消息转发") to_conn := UuidMapConn.Get(to_uuid).(*net.TCPConn) if SendByteStream(to_conn, pac.GetBytes()) != nil { // fmt.Println("发送失败转离线消息保存") dao.OfflineMsgAddMsg(to_uuid, string(pac.GetBytes())) report.AddCount(report.OfflineMsg, 1) } else { report.AddCount(report.OnlineMsg, 1) } } else { // fmt.Println("不在线转离线消息保存") dao.OfflineMsgAddMsg(to_uuid, string(pac.GetBytes())) report.AddCount(report.OfflineMsg, 1) } }
// 处理收发数据包 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)) } } } }
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 } } }
// 处理登陆 func HandleClientLogin(conn *net.TCPConn, recPacket *packet.Packet) { // read readMsg := &pb.PbClientLogin{} packet.Unpack(recPacket, readMsg) uuid := readMsg.GetUuid() // 检测uuid合法性 if dao.UuidCheckExist(uuid) { // 如果已经在线则关闭以前的conn if dao.UuidCheckOnline(uuid) { co := UuidMapConn.Get(uuid) if co != nil { CloseConn(co.(*net.TCPConn)) } } // 上线conn InitConn(conn, uuid) } else { CloseConn(conn) } // fmt.Println("uuid:", readMsg.GetUuid()) // fmt.Println("version:", readMsg.GetVersion()) // fmt.Println("timestamp:", convert.TimestampToTimeString(readMsg.GetTimestamp())) // write writeMsg := &pb.PbServerAcceptLogin{ Login: proto.Bool(true), TipsMsg: proto.String("登陆成功"), Timestamp: proto.Int64(time.Now().Unix()), } SendPbData(conn, packet.PK_ServerAcceptLogin, writeMsg) // 检查是否有该uuid的离线消息存在,若有,则发送其离线消息 if dao.OfflineMsgCheck(uuid) { // 这里比较复杂,后续再优化(可以多个离线消息一起发送) // 得到所有离线消息的id msgids := dao.OfflineMsgGetIds(uuid) // fmt.Println(uuid, "有离线消息,数量为:", len(msgids)) var ( k int err error ) for k, _ = range msgids { if err = SendByteStream(conn, []byte(dao.IdMsgGetMsgFromId(msgids[k]))); err != nil { break } // fmt.Println("正在发送离线消息", k, err, dao.IdMsgGetMsgFromId(msgids[k])) } if err != nil { if k != 0 { dao.OfflineMsgDeleteIds(uuid, msgids[k-1]) } } else { dao.OfflineMsgDeleteIds(uuid, msgids[k]) } } else { // fmt.Println("没有离线消息") } }
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 } } }