go开发聊天室(基于tcp协议)

此项目参照韩顺平老师教程,特此感谢。

项目结构如下:

client,server分别是客户端和服务端代码包,common为公共文件函数包;

main,model,processf分别存放主程序文件,结构体文件和方法文件,其中server下model中的Dao.go是redis连接池配置文件,引用了redis的git代码包地址:https://github.com/gomodule/redigo,下载后按说明引用。

运行项目:

1.开启服务端 

2.开启客户端(一个或多个)

3.注册并登录后显示

4.再登陆几个客户端,就可以互相发送消息和传送文件以及其他用户上下线服务端消息提醒了

代码如下:

server端:

main/main.go:

package main

 

import (

    "learn/chatroom/server/mainProcess"

    "learn/chatroom/server/model"

    "time"

)

func main() {

    //初始化连接池得到全局连接池变量pool

    model.PoolInit(8, 0, time.Second * 100, "tcp", "localhost:6379")

    //启动服务端进程

    mainProcess.GetMainProcess().OnlyProcess()

}

mainProcess/mainProcess.go:

package mainProcess

 

import (

    "fmt"

    "net"

    "learn/chatroom/common/utils"

    "learn/chatroom/common/message"

    "learn/chatroom/server/process"

)

 

type MainProcess struct {

    Conn net.Conn

}

 

func GetMainProcess() *MainProcess {

    return &MainProcess{}

}

func (this *MainProcess) OnlyProcess() {

    fmt.Println("server开始监听。。。")

    listen, err := net.Listen("tcp", "0.0.0.0:9999")

    if err != nil {

        fmt.Println("listen err=", err)

        return

    }

    defer listen.Close()

    for {

        fmt.Println("等待客户端连接。。。")

        //等待并返回下一个连接到该接口的连接

        conn, err_accp := listen.Accept()

        this.Conn = conn 

        if err_accp != nil {

            fmt.Println("err_accp=", err_accp)

        } else {

            fmt.Printf("客户端network=%v,ip=%v连接成功\n", conn.RemoteAddr().Network(), conn.RemoteAddr().String())

            //协程处理多个连接

            go this.process(conn) 

        }

        

    }

}

//登录后处理其他业务

func (this *MainProcess) process(conn net.Conn) {

    user := process.GetUserProcess(conn)

    defer conn.Close()

    defer func (){//匿名函数处理用户下线业务

        var uid int

        loggedUser := process.GetLoggedUser()

        //获取当前用户id

        for i, mp := range *loggedUser {

            for id, co := range mp {

                if co == conn {

                    uid = id

                    //去掉当前下线用户

                    *loggedUser = append((*loggedUser)[:i], (*loggedUser)[i + 1:]...)

                }

            }

        }

        //fmt.Println("unline uid=", uid)

        //说明未获取当前用户id

        if uid == 0 {

            return

        }

        //通知其他线上用户

        for _, mp := range *loggedUser {

            for _, co := range mp {

                if co == conn {

                    continue

                }

                user.NotifyOtherUsers(uid, co, 0)

            }

        }

    }()

    var mes, mes_back message.Message

    var  resmes message.ResMes

    for {

        err := utils.ReceiveMsg(conn, &mes)

        if err != nil {

            fmt.Println("服务器接受信息失败")

            return

        }

        switch mes.Type {

            case 1 ://登录类型请求

                user.DoLogin(mes, mes_back, resmes)

            case 2 ://注册类型请求

                user.DoRegister(mes, mes_back, resmes)

            case 3 ://显示在线用户

                user.ShowUserOnline(mes_back)

            case 4 ://用户发送消息

                user.SendMes(mes, mes_back)

            case 6 ://查看消息

                user.SearchMesList(mes, mes_back)

            case 7 ://发送文件

                user.SendFile(mes, mes_back)

        }

    }

}

model/Dao.go:

package model

 

import (

    "github.com/garyburd/redigo/redis"

    "time"

)

 

var pool *redis.Pool

 

func PoolInit(maxIdle int, maxActive int, idleTimeout time.Duration, network string, address string) {

    //初始化连接池

    pool = &redis.Pool{

        MaxIdle : maxIdle,

        MaxActive : maxActive,

        IdleTimeout : idleTimeout,

        Dial : func() (redis.Conn, error){

            return redis.Dial(network, address)

        },

    }

}

model/user.go:

package model

 

type User struct {

    UserId int `json:"id"`

    UserName string `json:"name"`

    UserPwd string `json:"pwd"`

}

model/userDao.go:

package model

 

import (

    "github.com/garyburd/redigo/redis"

    "fmt"

    "encoding/json"

    "learn/chatroom/common/message"

    "time"

)

 

type UserDao struct {

    Con redis.Conn

}

 

func NewUserDao() *UserDao {

    return &UserDao{pool.Get()}

}

//根据id获取user

func (this *UserDao) GetUserById(id int, user *User) error {

    user2, err := redis.String(this.Con.Do("hget", "users", id))

    if err != nil {

        fmt.Println("redis.String err=", err)

        return err

    }

    err = json.Unmarshal([]byte(user2), user)

    if err != nil {

        fmt.Println("json.Unmarshal err=", err)

        return err

    }

    return nil

}

//新增user

func (this *UserDao) AddUser(mes message.LoginMes) error {

    //先检查用户id是否重复

    user_old, _ := redis.String(this.Con.Do("hget", "users", mes.UserId))

    fmt.Println("user_old=", user_old)

    if user_old != "" {

        fmt.Println("用户已存在!!!")

        return fmt.Errorf("用户已存在!!!")

    }

    user := User{UserId : mes.UserId, UserName : mes.UserName, UserPwd : mes.UserPwd}

    userJson, err := json.Marshal(user)

    if err != nil {

        fmt.Println("userJson, err=", err)

        return err

    }

    _, err = this.Con.Do("hset", "users", mes.UserId, string(userJson))

    if err != nil {

        fmt.Println("hset user err=", err)

        return err

    }

    return nil

}

//保存消息

func (this *UserDao) SaveMes(uid int, toUid int, content string) error {

    str := fmt.Sprintf("%dto%d", uid, toUid)

    _, err := this.Con.Do("hset", str, time.Now().UnixNano(), content)

    if err != nil {

        fmt.Println("SaveMes hset err=", err)

        return err

    }

    return nil

//用户查看消息记录,由于redis包识别不了hgetall指令,姑只取一条作示例

func (this *UserDao) SearchMesList(idToId string) string {

    data, err := redis.String(this.Con.Do("hget", idToId, "1576641743776366500"))

    if err != nil {

        fmt.Println("hgetall idToId err=", err)

        return ""

    }

    return data

}

process/userManage.go:

package process

//已上线用户管理

import (

    "net"

)

type AllLoggedUser struct {

    LoggedUser []map[int]net.Conn

}

 

var (

    allLoggedUser AllLoggedUser

)

func GetLoggedUser() *[]map[int]net.Conn {

    return &allLoggedUser.LoggedUser

}

//已上线变量添加用户

func (this *AllLoggedUser) AddUser(id int, conn net.Conn) {

    mp := make(map[int]net.Conn)

    mp[id] = conn

    this.LoggedUser = append(this.LoggedUser, mp)

}

//已上线变量删除下线用户

func (this *AllLoggedUser) DelUser(id int) {

    for i, val := range this.LoggedUser {

        for uid, _ := range val {

            if uid == id {

                this.LoggedUser = append(this.LoggedUser[:i], this.LoggedUser[i + 1 :]...)

            }

        }

    }

    

}

process/userProcess.go:

package process

 

import (

    "learn/chatroom/common/message"

    "learn/chatroom/common/utils"

    "learn/chatroom/server/model"

    "encoding/json"

    "net"

    "fmt"

)

 

type UserProcess struct {

    Conn net.Conn

}

 

func GetUserProcess(conn net.Conn) *UserProcess {

    return &UserProcess{conn}

}

//登录

func (this *UserProcess) DoLogin(mes message.Message, mes_back message.Message, resmes message.ResMes)  {

    var data_login message.LoginMes

    var user model.User

    mes_back.Type = -1

    json.Unmarshal([]byte(mes.Data), &data_login)

    err := model.NewUserDao().GetUserById(data_login.UserId, &user)

    if err !=nil {

        resmes.Code = 300

        resmes.Msg = "未注册!!!"

    } else if data_login.UserPwd == user.UserPwd {

        resmes.Code = 200

        resmes.Msg = "服务端验证成功!!!"

        //通知其他线上用户

        for _, mp := range allLoggedUser.LoggedUser {

            for id, conn := range mp {

                if id == user.UserId {

                    continue //跳过自己

                }

                this.NotifyOtherUsers(data_login.UserId, conn, 1)

            }

        }

        //新增已登录用户到变量LoggedUser

        allLoggedUser.AddUser(user.UserId, this.Conn)

        


 

    } else {

        resmes.Code = 300

        resmes.Msg = "服务端验证失败!!!"

    }

    mesres_json, err := json.Marshal(resmes)

    mes_back.Data = string(mesres_json)

    err = utils.SendMsg(this.Conn, mes_back)

    if err != nil {

        fmt.Println("服务器反馈信息失败")

    }

}

//注册

func (this *UserProcess) DoRegister(mes message.Message, mes_back message.Message, resmes message.ResMes) {

    var data_login message.LoginMes

    mes_back.Type = -2

    json.Unmarshal([]byte(mes.Data), &data_login)

    err := model.NewUserDao().AddUser(data_login)

    if err !=nil {

        resmes.Code = 300

        resmes.Msg = "服务端新增用户失败!!!"

    } else {

        resmes.Code = 200

        resmes.Msg = "服务端新增用户成功!!!"

    }

    

    mesres_json, err := json.Marshal(resmes)

    mes_back.Data = string(mesres_json)

    err = utils.SendMsg(this.Conn, mes_back)

    if err != nil {

        fmt.Println("服务器反馈新增信息失败")

    }

}

//显示在线用户

func (this *UserProcess) ShowUserOnline(mes_back message.Message) {

    mes_back.Type = -3

    users := make([]model.User, 10)

    for _, mp := range allLoggedUser.LoggedUser {

        for id, _ := range mp {

            var user model.User

            model.NewUserDao().GetUserById(id, &user)

            users[id] = user

        }

    }

    loggedUserJson, err := json.Marshal(users)

    mes_back.Data = string(loggedUserJson)

    err = utils.SendMsg(this.Conn, mes_back)

    if err != nil {

        fmt.Println("服务器反馈在线用户信息失败")

    }

}

//用户向其他用户发送消息

func (this *UserProcess) SendMes(mes message.Message, mes_back message.Message) {

    var sendmes message.SendMes

    mes_back.Type = -4

    err := json.Unmarshal([]byte(mes.Data), &sendmes)

    if err != nil {

        fmt.Println("服务端反序列化sendmes失败!!!")

        return

    }

    last_content := fmt.Sprintf("%d said to %d:%s\n",sendmes.Uid, sendmes.ToUid, sendmes.Content)

    mes_back.Data = last_content

    //保存消息到redis

    err = model.NewUserDao().SaveMes(sendmes.Uid, sendmes.ToUid, last_content)

    if err != nil {

        return

    }

    //用以判断目标客户是否在线

    isOnline := false 

    //发送消息到对应的用户

    for _, mp := range allLoggedUser.LoggedUser {

        for id, conn := range mp {

            if id == sendmes.ToUid {

                isOnline = true

                err = utils.SendMsg(conn, mes_back)

            }

        }

    }

    if isOnline == false {//离线时,起一个携程监听客户上线再发送

        go this.WatchUserIsOnline(sendmes.ToUid, mes_back)

    }

}

//离线发送消息

func (this *UserProcess) WatchUserIsOnline(toUid int, mes_back message.Message) {

    boo := true

    for boo{

        for _, mp := range allLoggedUser.LoggedUser {

            for id, conn := range mp {

                if id == toUid {

                    err := utils.SendMsg(conn, mes_back)

                    if err != nil {

                        fmt.Println("服务端离线发送消息失败!!!")

                    }

                    boo = false

                }

            }

        }

    }

}

//通知其他用户上线 onlineOrUnline=1->上线,否则下线

func (this *UserProcess) NotifyOtherUsers(currentId int, conn net.Conn, onlineOrUnline int) {

    var mes message.Message

    var str string

    mes.Type = -5

    if onlineOrUnline == 1 {

        str = fmt.Sprintf("id为%d的用户已上线", currentId)

    } else {

        str = fmt.Sprintf("id为%d的用户已下线", currentId)

    }

    mes.Data = str

    err := utils.SendMsg(conn, mes)

    if err != nil {

        fmt.Println("服务端推送消息失败")

    }

}

 

//用户查看消息记录

func (this *UserProcess) SearchMesList(mes message.Message, mes_back message.Message) {

    content :=  model.NewUserDao().SearchMesList(mes.Data)

    mes_back.Type = -6

    mes_back.Data = content

    err := utils.SendMsg(this.Conn, mes_back)

    if err != nil {

        fmt.Println("服务端查询消息列表失败")

    }

}

//发送文件

func (this *UserProcess) SendFile(mes message.Message, mes_back message.Message) {

    var fileMes message.FileMes

    json.Unmarshal([]byte(mes.Data), &fileMes)

    mes_back.Type = -7

    mes_back.Data = mes.Data

    for _, mp := range allLoggedUser.LoggedUser {

        for id, conn := range mp {

            if id == fileMes.ToUid {

                err := utils.SendMsg(conn, mes_back)

                if err != nil {

                    fmt.Println("服务端发送文件失败!!!")

                }

            }

        }

    }

}

---------------------------------------------------------------------------分界线------------------------------------------------------------------------------------
client:

main/main.go:

package main

 

import (

    "fmt"

    "learn/chatroom/client/process"

    "net"

    "os"

)

 

func main() {

    var key int

    var loop = true

    var uid int

    var name string

    var pwd string

    conn := GetConn()

    for {

        mainMenu(&loop, &key)

        switch key {

            case 1 :

                toLogin(&uid, &pwd, conn)

                //登录后显示菜单

                process.ShowMenu(conn, uid)

            case 2 :

                toRegister(&uid, &name, &pwd, conn)

            case 3 :

                os.Exit(0)

        }

        

    }

    

}

 

func GetConn() net.Conn {

    //建立连接

    conn, err_conn := net.Dial("tcp", "192.168.2.149:9999")

    if err_conn != nil {

        fmt.Println("conn err =", err_conn)

    }

    return conn

}

func toLogin(uid *int, pwd *string, conn net.Conn){

    for {

        fmt.Println("请输入用户id")

        fmt.Scanln(uid)

        fmt.Println("请输入用户密码")

        fmt.Scanln(pwd)

        userProcess := process.GetUserProcess(conn)

        err_login := userProcess.DoLogin(uid, pwd)

        if err_login != nil {

            fmt.Println("用户名或密码错误,请重新输入")

        } else {

            break

        }

    }

}

 

func toRegister(uid *int, name *string, pwd *string, conn net.Conn) {

    for {

        fmt.Println("请输入用户id")

        fmt.Scanln(uid)

        fmt.Println("请输入用户暱称")

        fmt.Scanln(name)

        fmt.Println("请输入用户密码")

        fmt.Scanln(pwd)

        userProcess := process.GetUserProcess(conn)

        err := userProcess.DoRegister(uid, name, pwd)

        if err != nil {

            fmt.Println("注册失败,请重新输入")

        } else {

            break

        }

    }

    

}

func mainMenu(loop *bool, key *int) {

    for *loop {

        fmt.Println("------------------------欢迎使用多人聊天系统----------------------------")

        fmt.Println("\t\t\t 1 登录聊天室 ")

        fmt.Println("\t\t\t 2 注册用户 ")

        fmt.Println("\t\t\t 3 退出系统 ")

        fmt.Println("\t\t\t  请选择 1-3 ")

 

        fmt.Scanln(key)

        switch *key {

            case 1 : 

                fmt.Println(" 登录聊天室 ")

                *loop = false

            case 2 :

                fmt.Println(" 注册用户 ")

                *loop = false

            case 3 :

                fmt.Println(" 退出系统 ")

                *loop = false

            default :

                fmt.Println(" 输入错误,请重新输入 ")

        }

    }

}

model/user.go:

package model

 

type User struct {

    UserId int `json:"id"`

    UserName string `json:"name"`

    UserPwd string `json:"pwd"`

}

process/server.go:

package process

 

import (

    "fmt"

    "os"

    "net"

    "learn/chatroom/common/utils"

    "learn/chatroom/common/message"

    "learn/chatroom/client/model"

    "encoding/json"

    "io/ioutil"

)

//登录后菜单

func ShowMenu(conn net.Conn, uid int) {

    fmt.Println("-------------------恭喜xxx登陆成功----------------------")

    var num int 

    up := GetUserProcess(conn)

    for {

            fmt.Println(" 1.显示在线用户 ")

            fmt.Println(" 2.发送消息")

            fmt.Println(" 3.信息列表")

            fmt.Println(" 4.发送文件")

            fmt.Println(" 5.退出系统")

            fmt.Println("请选择1-4")

            fmt.Scanln(&num)

            switch num {

                case 1 :

                    up.ShowUserOnline()

                case 2 :

                    up.SendMes(uid)

                case 3 :

                    up.SearchMesList(uid)

                case 4 :

                    up.SendFile(uid)

                case 5 :

                    fmt.Println("退出系统")

                    os.Exit(0)

                default :

                    fmt.Println("输入错误,请重新输入")

            }

            

    }

}

//监听服务端推送消息

func ServerProcessMes(conn net.Conn) {

    //fmt.Println("ServerProcessMes 等待服务器消息")

    for {

        var mes message.Message

        err := utils.ReceiveMsg(conn, &mes)

        if err != nil {

            fmt.Println("ServerProcessMes utils.ReceiveMsg fail")

            return

        }

        //fmt.Println("ServerProcessMes 获取的mes=", mes)

        switch mes.Type {

            case -3 : 

                users := make([]model.User, 10)

                json.Unmarshal([]byte(mes.Data), &users)

                fmt.Println("在线用户如下:")

                for _, user := range users {

                    if user.UserId > 0 {

                        fmt.Printf("用户id=%d\tname=%s\tpwd=%s\n", user.UserId, user.UserName, user.UserPwd)

                    }

                    

                }

            case -4, -5, -6: 

                fmt.Println(mes.Data)

            case -7 :

                ReceiveFile(mes)

            default :

                fmt.Println("ServerProcessMes mes", mes)

        }

    }

}

//接受文件

func ReceiveFile(mes message.Message) {

    var fileMes message.FileMes

    json.Unmarshal([]byte(mes.Data), &fileMes)

    var path string

    path = fmt.Sprintf("d:/ctfiles/%s", fileMes.FileName)

    err := ioutil.WriteFile(path, fileMes.Content, 0666)

    if err != nil {

        fmt.Println("write err=", err)

    } else {

        str := fmt.Sprintf("接收用户id=%d的文件%s成功!!!", fileMes.Uid, fileMes.FileName)

        fmt.Println(str)

    }

}

process/userProcess.go:

package process

//客户端用户业务

import (

    "fmt"

    "learn/chatroom/common/message"

    "learn/chatroom/common/utils"

    "net"

    "encoding/json"

    "io/ioutil"

    "strings"

)

 

type UserProcess struct {

    Conn net.Conn

}

//实例化

func GetUserProcess(conn net.Conn) *UserProcess {

    return &UserProcess{Conn : conn}

}

//登录请求

func (this *UserProcess) DoLogin(uid *int, pwd *string ) error {

    //mes为发送到服务端信息,mes_back为服务端反馈信息

    var mes, mes_back message.Message

    logmes := message.LoginMes{UserId : *uid, UserPwd : *pwd}

    mes.Type = 1

    loginJson, err := json.Marshal(logmes)

    if err != nil {

        fmt.Println("logindata marshal err=", err)

        return err

    }

    mes.Data = string(loginJson)

    err_send := utils.SendMsg(this.Conn, mes)

    if err_send != nil {

        return err_send

    }

    err_receive := utils.ReceiveMsg(this.Conn, &mes_back)

    if err_receive != nil {

        fmt.Println("客户端接收反馈信息失败")

        return err_receive

    }

    //resmes为服务端反馈的具体信息

    var resmes message.ResMes

    json.Unmarshal([]byte(mes_back.Data), &resmes)

    //反馈登陆成功

    if mes_back.Type == -1 && resmes.Code == 200 {

        fmt.Println(resmes)

        //监听服务端的消息,如好友上线,发来消息等

        go ServerProcessMes(this.Conn)

        return nil

    }

    return fmt.Errorf("客户端接收反馈信息错误")

}

//注册请求

func (this *UserProcess) DoRegister(uid *int, name *string, pwd *string) (err error) {

    //mes为发送到服务端信息,mes_back为服务端反馈信息

    var mes, mes_back message.Message

    logmes := message.LoginMes{UserId : *uid, UserName : *name, UserPwd : *pwd}

    mes.Type = 2

    registerJson, err := json.Marshal(logmes)

    if err != nil {

        fmt.Println("register-data marshal err=", err)

        return 

    }

    mes.Data = string(registerJson)

    err = utils.SendMsg(this.Conn, mes)

    if err != nil {

        return 

    }

    err = utils.ReceiveMsg(this.Conn, &mes_back)

    if err != nil {

        fmt.Println("客户端接收反馈信息失败")

        return 

    }

    //resmes为服务端反馈的具体信息

    var resmes message.ResMes

    json.Unmarshal([]byte(mes_back.Data), &resmes)

    //反馈注册成功

    if mes_back.Type == -2 && resmes.Code == 200 {

        fmt.Println(resmes.Msg)

        err = nil

        return 

    }

    err = fmt.Errorf("客户端接收反馈信息错误")

    return

}

//显示在线用户

func (this *UserProcess) ShowUserOnline() {

    var mes message.Message

    mes.Type = 3

    err := utils.SendMsg(this.Conn, mes)

    if err != nil {

        fmt.Println("客户端发送反馈信息失败")

        return 

    }

}

//用户发送消息

func (this *UserProcess) SendMes(uid int) {

    var toUid int

    var content string

    fmt.Println("请输入想聊天对象的id:")

    fmt.Scanln(&toUid)

    fmt.Println("请输入聊天内容:")

    fmt.Scanln(&content)

    fmt.Printf("%d said to %d: %s\n", uid, toUid, content)

    var mes message.Message

    mes.Type = 4

    var dataSend message.SendMes

    dataSend.Uid = uid

    dataSend.ToUid = toUid

    dataSend.Content = content

    dataJson, err := json.Marshal(dataSend)

    mes.Data= string(dataJson)

    if err != nil {

        fmt.Println("json.Marshal(data)失败")

        return 

    }

    err = utils.SendMsg(this.Conn, mes)

    if err != nil {

        fmt.Println("客户端发送信息失败")

        return 

    }

}

//查看消息列表

func (this *UserProcess) SearchMesList(uid int) {

    var toid int

    var mes message.Message

    fmt.Println("请输入目标用户的id")

    fmt.Scanln(&toid)

    content := fmt.Sprintf("%dto%d", uid, toid)

    mes.Type = 6

    mes.Data = content

    err := utils.SendMsg(this.Conn, mes)

    if err != nil {

        fmt.Println("查看消息列表失败")

    }

}

//发送文件

func (this *UserProcess) SendFile(uid int) {

    var filePath string

    var toUid int

    var fileName string

    var mes message.Message

    var fileMes message.FileMes

    fmt.Println("请输入文件地址:")

    fmt.Scanln(&filePath)

    fmt.Println("请输入接收对象id:")

    fmt.Scanln(&toUid)

    //判断文件是否存在

    ok, _ := utils.PathExists(filePath)

    if !ok {

        fmt.Println("文件夹不存在!!!")

        return

    }

    //获取文件名和内容

    strs := strings.Split(filePath, "/")

    fileName = strs[len(strs) - 1]

    content, err_cont := ioutil.ReadFile(filePath)

    if err_cont != nil {

        fmt.Println("读取文件内容失败!!!")

        return

    }

    //封装消息体

    fileMes.Uid = uid

    fileMes.ToUid = toUid

    fileMes.FileName = fileName

    fileMes.Content = content

    fileJson, _ := json.Marshal(fileMes)

 

    mes.Type = 7

    mes.Data = string(fileJson)

    err := utils.SendMsg(this.Conn, mes)

    if err != nil {

        fmt.Println("发送文件失败!!!")

    }

    fmt.Println("发送文件成功!!!")

}

--------------------------------------------------------------------------------------分界线-------------------------------------------------------------------------

common:

message/message.go:

package message

 

type Message struct {

    //类型 1-登录-1-登陆反馈 2-注册 -2 -注册反馈 3-显示在线用户 -3,-显示在线用户反馈 4-用户向用户发送信息 -4,反馈 -5,-服务器推送消息

    //6-用户查看消息列表 -6,反馈 7-用户发送文件 -7,反馈

    Type int 

    Data string //数据 

}

 

type LoginMes struct {

    UserId int `json:"id"`

    UserPwd string `json:"pwd"`

    UserName string `json:"name"`

}

 

type ResMes struct {

    Code int //返回状态码 100-未注册 200-成功  300-失败

    Msg string //信息

}

 

type SendMes struct {

    Uid int `json:"uid"`

    ToUid int `json:"touid"`

    Content string `json:"content"`

}

type FileMes struct {

    Uid int

    ToUid int

    FileName string

    Content []byte

}

utils/cli_to_ser.go:

package utils

//客户端和服务端相互推送消息

import (

    "net"

    "learn/chatroom/common/message"

    "encoding/json"

    "encoding/binary"

    "fmt"

    "os"

)

 

func SendMsg(conn net.Conn, mes message.Message) error {

    mesJson, err_mesJson := json.Marshal(mes)

    if err_mesJson != nil {

        fmt.Println("mes marshal err=", err_mesJson)

        return err_mesJson

    }

    //定义传输字节长度

    meslen := uint32(len(mesJson))

    buf := make([]byte, 4)

    //uint32转成[]byte,以便conn.Write()

    binary.BigEndian.PutUint32(buf[:4], meslen)  

    //发送数据长度

    n, err_write := conn.Write(buf[:4])

    if err_write !=nil || n != 4 {

        fmt.Println("mes-length write err=", err_write)

        return err_write

    }

    //fmt.Printf("发送了%v个字节\n", len(mesJson))

    //fmt.Println("发送的data=", string(mesJson))

    //发送登录数据

     _, err_write = conn.Write(mesJson)

    if err_write !=nil {

        fmt.Println("mes-data write err=", err_write)

        return err_write

    } 

    return nil

}

 

func ReceiveMsg(conn net.Conn, mes *message.Message) (error){

    //定义接收字节变量

    buf := make([]byte, 8192)

    //conn.Read()等待客户端发送消息,如果没有write[发送],那么协程阻塞在这里

    //读取前四个字节,数据长度

    n, err := conn.Read(buf[:4])

    if err != nil || n != 4 {

        fmt.Println("server read len err=", err)

        fmt.Println("客户端退出。。。")

        return err

    }

    //获取接受的数据长度。将[]byte转成uint32

    data_len := binary.BigEndian.Uint32(buf[:4])

    //接收已知长度的数据

    n, err = conn.Read(buf[:data_len])

    if n != int(data_len) || err !=nil {

        fmt.Println("server read data err=", err)

        fmt.Println("客户端退出。。。")

        return err

    }

    //fmt.Println("接收到的data_len=", data_len)

    //fmt.Println("接收到的data=", string(buf[:data_len]))

    json.Unmarshal(buf[:data_len], mes)

    return nil

}

 

//判断文件文件是否存在

func PathExists(path string) (bool, error) {

    _, err := os.Stat(path)

    if err == nil {

        return true, nil

    }

    if os.IsNotExist(err) {

        return false, nil

    }

    return false, err

}

以上就是全部

 

 

 

 

发布了29 篇原创文章 · 获赞 6 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章