func login(userId int, userPwd string) (err error) {
	//下一步就要开始定协议..
	//fmt.Printf("userId = %d userPwd = %s\n",userId,userPwd)
	//return nil
	//1.链接到服务器
	conn, err := net.Dial("tcp", "localhost:8889")
	if err != nil {
		fmt.Println("net.Dial err=", err)
		return
	}
	//延时关闭
	defer conn.Close()
	//2.准备通过conn发送消息给服务器
	var mes message.Message
	mes.Type = message.LoginMesType
	//3.创建一个LoginMes结构体
	var loginMes message.LoginMes
	loginMes.UserId = userId
	loginMes.UserPwd = userPwd

	//4.将loginMes序列化
	data, err := json.Marshal(loginMes)
	if err != nil {
		fmt.Println("json.Marshal err= ", err)
		return
	}
	//5.将data赋给mes.Data字段
	mes.Data = string(data)
	//type Message struct {
	//Type string `json:"type"`//消息类型
	//Data string `json:"data"`//消息的内容
	//}

	//6.将mes进行序列化 最后这个数据就是我们要发送的数据了 他是一个byte切片
	data, err = json.Marshal(mes)
	if err != nil {
		fmt.Println("json.Marshal err= ", err)
		return
	}
	//7.到这个时候 data就是我们要发送的消息
	//7.1先把data的长度发送给服务器
	//而conn.Write接受的数据类型是byte切片,所以首先要获取到data的长度->转成一个表示长度的byte切片
	var pkglen uint32 //先定义包的长度,因为他说一会要发送的所以定义成unit32类型的,使用type ByteOrder来转换成byte类型的
	pkglen = uint32(len(data))
	var buf [4]byte
	binary.BigEndian.PutUint32(buf[0:4], pkglen)
	//现在就可以发送了
	n, err := conn.Write(buf[:4])
	if n != 4 || err != nil {
		fmt.Println("conn.Write(bytes) fail", err)
		return
	}
	fmt.Println("客户端发送的消息长度成功")
	return
	
}
	var pkglen uint32 //先定义包的长度,因为他说一会要发送的所以定义成unit32类型的,使用type                                 
                      //ByteOrder来转换成byte类型的
	pkglen = uint32(len(data))
                      //因为conn.Write的接受的数据类型是byte数组,而	            
                      //binary.BigEndian.PutUint32,需要将unit型的才能转为byte数组
	var buf [4]byte
	binary.BigEndian.PutUint32(buf[0:4], pkglen)
	//现在就可以发送了
	n, err := conn.Write(buf[:4])

 Conn的官方文档,Write(b []byte) (n int, err error)

type Conn
type Conn interface {
    // Read从连接中读取数据
    // Read方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Read(b []byte) (n int, err error)
    // Write从连接中写入数据
    // Write方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Write(b []byte) (n int, err error)
    // Close方法关闭该连接
    // 并会导致任何阻塞中的Read或Write方法不再阻塞并返回错误
    Close() error
    // 返回本地网络地址
    LocalAddr() Addr
    // 返回远端网络地址
    RemoteAddr() Addr
    // 设定该连接的读写deadline,等价于同时调用SetReadDeadline和SetWriteDeadline
    // deadline是一个绝对时间,超过该时间后I/O操作就会直接因超时失败返回而不会阻塞
    // deadline对之后的所有I/O操作都起效,而不仅仅是下一次的读或写操作
    // 参数t为零值表示不设置期限
    SetDeadline(t time.Time) error
    // 设定该连接的读操作deadline,参数t为零值表示不设置期限
    SetReadDeadline(t time.Time) error
    // 设定该连接的写操作deadline,参数t为零值表示不设置期限
    // 即使写入超时,返回值n也可能>0,说明成功写入了部分数据
    SetWriteDeadline(t time.Time) error
}

使用binary的ByteOrder进行数据类型的转换 

package binary
import "encoding/binary"

binary包实现了简单的数字与字节序列的转换以及变长值的编解码。
type ByteOrder
type ByteOrder interface {
    Uint16([]byte) uint16
    Uint32([]byte) uint32
    Uint64([]byte) uint64
    PutUint16([]byte, uint16)
    PutUint32([]byte, uint32)
    PutUint64([]byte, uint64)
    String() string
}
ByteOrder规定了如何将字节序列和 16、32或64比特的无符号整数互相转化。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐