简单即时通讯

客户端输入用户名和密码

服务器验证用户名和密码,验证成功返回给客户端

  • 定义协议 message.go
package message

var (
    LoginMesType   = "LoginMes"
    LoginResMesType = "LoginResMes"
)

//登录协议
type LoginMes struct {
    UserId  int    `json:"user_id"`
    UserPwd string `json:"user_pwd"`
    UserName string `json:"user_name"`
}

//发送协议
type Message struct {
    Type string `json:"type"`
    Data string `json:"data"`
}

//返回协议
type LoginResMes struct {
    Code  string `json:"code"`
    Error string `json:"error"`
}

客户端
login.go

package main

import (
    "chat/common/message"
    "encoding/binary"
    "encoding/json"
    "fmt"
    "net"
)

//接受
func readPkg(conn net.Conn) (mes message.Message, err error) {

    buf := make([]byte, 8096)
    fmt.Println("读取客户端发送的数据")
    //第一次读
    _, err = conn.Read(buf[:4]) //读4个
    if err != nil {
        fmt.Println("Read err=", err)
        return
    }
    //fmt.Println("服务器读到的n=", n)
    //buf[:4]转一个uint32
    var pkgLen uint32
    pkgLen = binary.BigEndian.Uint32(buf[0:4])
    //第二次读
    n, err := conn.Read(buf[:pkgLen])

    if n != int(pkgLen) || err != nil {
        return
    }



    err = json.Unmarshal(buf[:pkgLen], &mes)

    if err != nil {
        fmt.Println("json.Unmarshal(buf[0:pkgLen],&mes) err=", err)
        return
    }

    return
}

//发送
func Write(conn net.Conn, data []byte) (err error) {
    var pkgLen uint32
    pkgLen = uint32(len(data))
    var buf [4]byte
    binary.BigEndian.PutUint32(buf[0:4], pkgLen)
    //发送长度
    n, err := conn.Write(buf[0:4])
    if err != nil {
        fmt.Println("conn.Write(buf[0:4]) err=", err)
        return
    }
    //发送内容
    n, err = conn.Write(data)
    if n != int(pkgLen) || err != nil {
        fmt.Println("conn.Write(data) err=", err)
        return
    }
    return
}

func login(userId int, userPwd string) (err error) {
    conn, err := net.Dial("tcp", "127.0.0.1:8899")
    if err != nil {
        fmt.Println("64=>连接错误,err=", err)
    }

    defer conn.Close()

    //2准备跳过conn发送消息给服务器
    var loginMes message.LoginMes
    loginMes.UserId = userId
    loginMes.UserPwd = userPwd

    data, err := json.Marshal(loginMes)
    if err != nil {
        fmt.Println("line 55=>json.Marshal(loginMes) err =", err)
        return
    }
    var mes message.Message
    mes.Type=message.LoginMesType
    mes.Data = string(data) //把data赋值给mes.Data
    data, err = json.Marshal(mes)
    fmt.Println(data)
    if err != nil {
        fmt.Println("line 55=>json.Marshal(loginMes) err =", err)
        return
    }

    //import "encoding/binary"
    //binary包实现了简单的数字与字节序列的转换以及变长值的编解码。
    var pkgLen uint32
    pkgLen = uint32(len(data))
    var buf [4]byte
    //func (bigEndian) PutUint32(b []byte, v uint32) {
    //参数v 是uint32类型的值
    binary.BigEndian.PutUint32(buf[0:4], pkgLen)
    //buf[0:4]  [0 0 0 48]
    _, err = conn.Write(buf[0:4])
    if err != nil {
        fmt.Println("80line 发送长度失败 err=", err)
        return
    }
    fmt.Printf("客户端,发送消息的长度=%d,内容为%s", len(data), string(data))

    _, err = conn.Write(data)
    if err != nil {
        fmt.Println("80line 发送长度失败 err=", err)
        return
    }

    //读服务器返回的信息
    mes ,err = readPkg(conn)
    fmt.Println("读取到服务器返回数据==",mes)
    if err != nil {
        fmt.Println(" readPkg(conn) err=",err)
    }
    fmt.Println("mes=",mes)
    var LoginResMes message.LoginResMes
    err =json.Unmarshal([]byte(mes.Data),&LoginResMes)
    if err != nil {
        fmt.Println(" json.Unmarshal([]byte(mes.Data),&LoginResMes) err=",err)
    }

    if LoginResMes.Code == "200" {
        fmt.Println("登录成功~~~哈哈")
    }
    return
}

server.go

package main

import (
    "chat/common/message"
    "encoding/binary"
    "encoding/json"
    "fmt"
    "io"
    "net"
)

//接受
func readPkg(conn net.Conn) (mes message.Message, err error) {

    buf := make([]byte, 8096)
    fmt.Println("读取客户端发送的数据")
    //第一次读
    _, err = conn.Read(buf[:4]) //读4个
    if err != nil {
        fmt.Println("Read err=", err)
        return
    }
    //fmt.Println("服务器读到的n=", n)
    //buf[:4]转一个uint32
    var pkgLen uint32
    pkgLen = binary.BigEndian.Uint32(buf[0:4])
    //第二次读
    n, err := conn.Read(buf[:pkgLen])

    if n != int(pkgLen) || err != nil {
        return
    }
    err = json.Unmarshal(buf[:pkgLen], &mes)
    if err != nil {
        fmt.Println("json.Unmarshal(buf[0:pkgLen],&mes) err=", err)
        return
    }

    return
}

//发送
func Write(conn net.Conn, data []byte) (err error) {
    var pkgLen uint32
    pkgLen = uint32(len(data))
    var buf [4]byte
    binary.BigEndian.PutUint32(buf[0:4], pkgLen)
    //发送长度
    n, err := conn.Write(buf[0:4])
    if err != nil {
        fmt.Println("conn.Write(buf[0:4]) err=", err)
        return
    }
    //发送内容
    n, err = conn.Write(data)
    if n != int(pkgLen) || err != nil {
        fmt.Println("conn.Write(data) err=", err)
        return
    }
    return
}

//处理和客户端的通讯
func process(conn net.Conn) {
    //延时关闭
    defer conn.Close()

    for {
        fmt.Println("客户端连接........")
        mes, err := readPkg(conn)
        if err != nil {
            if err == io.EOF {
                fmt.Println("客户端退出,服务器也退出")
                return
            } else {
                fmt.Println("readPkg err =", err)
                return
            }
        }
        var LoginMes message.LoginMes
        json.Unmarshal([]byte(mes.Data), &LoginMes)
        var LoginResMes message.LoginResMes
        if  LoginMes.UserId == 100 && LoginMes.UserPwd == "root" {
            LoginResMes.Code = "200"
            LoginResMes.Error="登录成功"
        } else {
            LoginResMes.Code = "500"
            LoginResMes.Error="登录失败"
        }

        //准备好数据发送给客户端
        var resMsg message.Message
        resMsg.Type = message.LoginResMesType
        data, err := json.Marshal(LoginResMes)

        if err != nil {
            fmt.Println("json.Marshal(LoginResMes) err=", err)
        }
        resMsg.Data = string(data)

        data, err = json.Marshal(resMsg)
        if err != nil {
            fmt.Println("json.Marshal(resMsg) err=", err)
        }

        //发送长度
        err = Write(conn, data)
        return
    }
}

func main() {

    listen, err := net.Listen("tcp", "127.0.0.1:8899")

    if err != nil {
        fmt.Println("listen err=", err)
    }
    defer listen.Close()

    for {
        conn, err := listen.Accept()
        if err != nil {
            fmt.Println("Accept err=", err)
        }
        go process(conn)
    }

}
本作品采用《CC 协议》,转载必须注明作者和本文链接
有梦想的人睡不着,没有梦想的人睡不醒。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
文章
88
粉丝
21
喜欢
134
收藏
267
排名:228
访问:4.2 万
私信
所有博文
博客标签
redis
1
php
1
laravel
7
docker
3
orm
2
sync
1
pivot
1
detach
2
attach
2
算法
1
递归
1
多对多
1
lnmp环境搭建
1
GO变量
1
GO数据类型
1
IOC注入反转
1
IOC容器的绑定解析过程(绑定单例)
1
原生微信网页授权登录(natapp穿墙)
1
VMwareNAT网卡配置
1
MySQL基础架构
1
redis 主从搭建
1
Sentinel哨兵模式解决故障转移
1
elasticsearch安装
1
elasticsearch集群安装3台
1
安装kibana
1
必须了解的mysql三大日志-binlog、redo log和undo log
1
何处理数据恢复 数据丢失 面试tx的架构师的岗位问的
1
分库分表插入数据
1
创建分库分表(在主从复制的基本上)
1
分库分表总结
1
mysql总结
1
haproxy状态检测脚本(完成高可用)
1
mysql高可用衡搭建(Keepalived)
1
mysql负载均衡搭建(haproxy)
1
mysql主从恢复数据一致性(pt工具-t-table-checksum和pt-table-sync)
1
终于解决了《====》记一次mysql热备份xtrabackup(没有解决问题)
1
mysql事务
1
MYSQL8.0安装
1
Redis-cluster分布式集群搭建部署
1
比Redis-cluster还好的redis分布式集群(twemproxy)
1
Redis缓存穿透/缓存雪崩/缓存击穿(案例:产生的原因 解决方案利/弊)
1
数据结构之MySQL独爱B+树(二叉树、AVL树、红黑树、B树对比)
1
B-tree
1
B+tree
1
Mycat实现mysql的负载均衡读写分离
2
mysql双主双从 搭建配置
1
mycat 双主双从-负载均衡-高可用
1
Mycat垂直分库
1
记一次mysql高可用技术分享
1
【rabbitmq】安装ampq的扩展的踩坑总结
1
PHP操作MongoDB(增删改查)
1
golang总结
5
社区赞助商