(初学者)使用go搭建简单的服务器(计算器)

通讯协议

proto

CS // 客户端到服务器 
SC // 服务器到客户端

proto:
	type csproto struct { // 两个数字
		a int
		b int
	}
	type scproto struct { // 结果
		ans int 
	}
	// 判断是什么指令协议在更上一层
	type data name {
		msg_id int // 操作id
		msg_data []byte // 前一个协议的字节数据
	}

uml

client server add/sub/mul/div req ans res client server

使用方式

先调用服务器端TCPServerStart
再调用客户端TCPClientStrat
接着即可在服务器端输入数据获得结果

ex:

TCPServerStart("127.0.0.1:9099")
TCPClientStrat("127.0.0.1:9099")

效果

绿色字为输入数字

服务器端

package Tcp

import (
	proto "../tcp_proto"
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	. "net"
)

const (
	Add      int = 0
	Sub      int = 1
	Mul      int = 2
	Div      int = 3
)

type csproto struct {
	A int `json:"a"` // json 用法, 大写才能被识别,使用`json:"a"`可以将其变成小写
	B int `json:"b"`
}

type scproto struct {
	Ans int `json:"ans"`
}

type client struct {
	ch chan msg
	conn Conn
}

type msg struct {
	Msg_id int
	Data []byte
}

type cliMsg struct {
	cli client
	msg_id int
	data []byte
}


func (cli client)send(ch chan msg){
	for {
		send_msg := <-ch
		msg_id, data := send_msg.Msg_id, send_msg.Data
		fmt.Println("send", msg_id)
		data, err := proto.Packet(msg_id, data)
		if err != nil {
			fmt.Println("Packet fail, err:", err)
			return
		}
		cli.conn.Write(data)
	}
}

func (cli client)receive(ch chan cliMsg){
	defer cli.conn.Close()  // 关闭连接
	reader := bufio.NewReader(cli.conn)
	for {
		msg_id, data_byte, err := proto.Unpack(reader)
		if err == io.EOF{
			return
		}
		if err != nil{
			fmt.Println("Unpack fail, err:", err)
			return
		}
		var csmsg csproto
		json.Unmarshal(data_byte, &csmsg)
		fmt.Println(msg_id, csmsg)
		reivece_msg := cliMsg{cli,msg_id,data_byte}
		ch <- reivece_msg
	}
}

func add(data []byte)(int, []byte) {
	var csmsg csproto
	var scmsg scproto
	json.Unmarshal(data, &csmsg)
	scmsg.Ans = csmsg.A + csmsg.B
	data, err := json.Marshal(scmsg)
	if err != nil {
		fmt.Println("encode fail, err:", err)
	}
	return 0, data
}

func sub(data []byte)(int, []byte) {
	var csmsg csproto
	var scmsg scproto
	fmt.Print("sub")
	json.Unmarshal(data, &csmsg)
	scmsg.Ans = csmsg.A - csmsg.B
	data, err := json.Marshal(scmsg)
	if err != nil {
		fmt.Println("encode fail, err:", err)
	}
	return 1, data
}

func mul(data []byte)(int, []byte) {
	var csmsg csproto
	var scmsg scproto
	json.Unmarshal(data, &csmsg)
	scmsg.Ans = csmsg.A * csmsg.B
	data, err := json.Marshal(scmsg)
	if err != nil {
		fmt.Println("encode fail, err:", err)
	}
	return 2, data
}

func div(data []byte) (int, []byte) {
	var csmsg csproto
	var scmsg scproto
	json.Unmarshal(data, &csmsg)
	if csmsg.B == 0 {
		fmt.Println("error, Dividend is zero")
		return 10, nil
	}
	scmsg.Ans = csmsg.A / csmsg.B
	data, err := json.Marshal(scmsg)
	if err != nil {
		fmt.Println("encode fail, err:", err)
	}
	return 3, data
}

func handle_data(proch chan cliMsg){
	for {
		select {
		case cli_msg := <- proch:
			msg_id, data := cli_msg.msg_id, cli_msg.data
			switch {
			case msg_id == Add:
				cli_msg.msg_id, cli_msg.data = add(data)
			case msg_id == Sub:
				cli_msg.msg_id, cli_msg.data = sub(data)
			case msg_id == Mul:
				cli_msg.msg_id, cli_msg.data = mul(data)
			case msg_id == Div:
				cli_msg.msg_id, cli_msg.data = div(data)
			}
			proch <- cli_msg
		}
	}
}

func handle(unch, proch chan cliMsg)  { // 消息转发站,可以省略直接处理
	var cli_msg cliMsg
	for {
		select {
		case cli_msg = <-unch: // 收到未处理的信息
			proch <- cli_msg // 不会被当前goroutine接收到,发送给 // 先检查其他线程有没有proch接收消息,最后检查当前线程
		case cli_msg = <-proch: // 收到已处理的信息
			cli_ch := cli_msg.cli.ch
			pro_msg := msg{cli_msg.msg_id, cli_msg.data}
			cli_ch <- pro_msg // 发送给对应的send
		}
	}
}

func TCPServerStart(port string) {
	fmt.Println("tcp server start!")
	listen, err := Listen("tcp", port)
	if err != nil {
		fmt.Println("tcp server listen fail, err:", err)
	}
	unch, proch := make(chan cliMsg, 20), make(chan cliMsg, 20)
	go handle(unch, proch)
	go handle_data(proch)
	for {
		conn, err := listen.Accept() // 建立连接
		if err != nil {
			fmt.Println("server accept fail, err:", err)
			continue
		}
		fmt.Println("connect")
		cli_ch := make(chan msg, 20)
		cli := client{cli_ch,conn}
		go cli.receive(unch)
		go cli.send(cli_ch)
	}
}

客户端

package Tcp

import (
	proto "../tcp_proto"
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"net"
)

const (
	Quit      int = 0
	Addc      int = 1
	Subc      int = 2
	Mulc      int = 3
	Divc      int = 4
	ERROR     int = 10
)

var (
	chadd chan []byte
	chsub chan []byte
	chmul chan []byte
	chdiv chan []byte
	chsend chan msg
	)

func sendc(conn net.Conn) {
	for {
		chsend = make(chan msg, 20)
		msg := <- chsend
		msg_id := msg.Msg_id
		msg_id--
		data, err := proto.Packet(msg_id, msg.Data)
		if err != nil {
			fmt.Println("encode fail, err:", err)
		}

		conn.Write(data)

	}
}

func receivec(conn net.Conn)  {
	chadd = make(chan []byte, 20)
	chsub = make(chan []byte, 20)
	chmul = make(chan []byte, 20)
	chdiv = make(chan []byte, 20)
	defer conn.Close()  // 关闭连接
	reader := bufio.NewReader(conn)
	for {
		msg_id, data_byte, err := proto.Unpack(reader)
		if err == io.EOF{
			return
		}
		if err != nil{
			fmt.Println("Unpack fail, err:", err)
			return
		}

		msg_id++
		switch {
		case msg_id == Addc:chadd <- data_byte
		case msg_id == Subc:chsub <- data_byte
		case msg_id == Mulc:chmul <- data_byte
		case msg_id == Divc:chdiv <- data_byte
		case msg_id == ERROR:// error 处理
		}
	}
}

func addc()  {
	for {
		fmt.Println("Please enter two addends, enter 0, 0 to return to the previous level")
		var a, b, ans int
		fmt.Scanf("%d %d", &a, &b)
		if a == 0 && b == 0 {
			return
		}

		var csmsg = csproto{a,b}
		csdata, err := json.Marshal(csmsg)
		if err != nil {
			fmt.Println("encode fail, err:", err)
		}
		var msgc = msg{Addc,csdata}
		chsend <- msgc

		data := <- chadd
		var scmsg scproto
		json.Unmarshal(data, &scmsg)
		ans = scmsg.Ans
		fmt.Printf("%d + %d = %d\n", a, b, ans)
	}
}

func subc()  {
	for {
		fmt.Println("Please subtract and subtract, enter 0, 0 to return to the previous level")
		var a, b, ans int
		fmt.Scanf("%d %d", &a, &b)
		if a == 0 && b == 0 {
			return
		}

		var csmsg = csproto{a,b}
		csdata, err := json.Marshal(csmsg)
		if err != nil {
			fmt.Println("encode fail, err:", err)
		}
		var msgc = msg{Subc,csdata}
		chsend <- msgc

		data := <- chsub
		var scmsg scproto
		json.Unmarshal(data, &scmsg)
		ans = scmsg.Ans
		fmt.Printf("%d - %d = %d\n", a, b, ans)
	}
}

func mulc()  {
	for {
		fmt.Println("Please enter two multipliers, enter 0, 0 to return to the previous level")
		var a, b, ans int
		fmt.Scanf("%d %d", &a, &b)
		if a == 0 && b == 0 {
			return
		}

		var csmsg = csproto{a,b}
		csdata, err := json.Marshal(csmsg)
		if err != nil {
			fmt.Println("encode fail, err:", err)
		}
		var msgc = msg{Mulc,csdata}
		chsend <- msgc

		data := <- chmul
		var scmsg scproto
		json.Unmarshal(data, &scmsg)
		ans = scmsg.Ans
		fmt.Printf("%d * %d = %d\n", a, b, ans)
	}
}

func divc()  {
	for {
		fmt.Println("Please divisor and dividend, enter 0, 0 to return to the previous level")
		var a, b, ans int
		fmt.Scanf("%d %d", &a, &b)
		if a == 0 && b == 0 {
			return
		}
		if b == 0 {
			fmt.Println("dividend is zero, restart")
			continue
		}

		var csmsg = csproto{a,b}
		csdata, err := json.Marshal(csmsg)
		if err != nil {
			fmt.Println("encode fail, err:", err)
		}
		var msgc = msg{Divc,csdata}
		chsend <- msgc

		data := <- chdiv
		var scmsg scproto
		json.Unmarshal(data, &scmsg)
		ans = scmsg.Ans
		fmt.Printf("%d / %d = %d\n", a, b, ans)
	}
}


func TCPClientStrat(addr string) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		fmt.Println("connect fail, err:", err)
		return
	}

	defer conn.Close()
	go sendc(conn)
	go receivec(conn)

	for {
		fmt.Println("Please choose an operation:")
		fmt.Println("1 add\n2 sub\n3 mul\n4 div\n0 quit")
		var ot int
		fmt.Scanf("%d", &ot)
		switch {
		case ot == Quit:
			return
		case ot == Addc:
			addc()
			break
		case ot == Subc:
			subc()
			break
		case ot == Mulc:
			mulc()
			break
		case ot == Divc:
			divc()
			break
		}
	}
}

tcp封包解包协议

package tcp_proto

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"encoding/json"
)

type MsgDate struct {
	Msg_id int `json:"msg_id"`
	Date []byte `json:"date"`
}

// Encode 将消息编码
func Packet(msg_id int, data []byte)([]byte, error)  {
	// 读取消息的长度,转换成int32类型(占4个字节)
	msg := MsgDate{msg_id,data}

	msg_bytes, err:= json.Marshal(msg)
	if err != nil{
		return nil, err
	}

	length := int32(len(msg_bytes))
	var pkg = new(bytes.Buffer)

	//写入消息头
	err = binary.Write(pkg, binary.LittleEndian, length)
	if err != nil{
		return nil, err
	}

	//写入消息实体
	err = binary.Write(pkg, binary.LittleEndian, msg_bytes)
	if err != nil{
		return nil, err
	}
	return pkg.Bytes(), nil
}

// Decode 消息解码
func Unpack(reader *bufio.Reader)(int, []byte, error)  {
	//读取消息长度
	lengthByte, _ := reader.Peek(4) //读取前4个字节数据
	lengthBuff := bytes.NewBuffer(lengthByte)

	var length int32
	err := binary.Read(lengthBuff, binary.LittleEndian, &length)
	if err != nil{
		return 0, nil, err
	}

	// Buffered返回缓冲中现有的可读取的字节数。
	if int32(reader.Buffered()) < length + 4 {
		return 0, nil, err
	}

	//读取真正的消息数据
	pack := make([]byte,int(4 + length))
	_, err = reader.Read(pack)
	if err != nil{
		return 0, nil, err
	}
	var msg MsgDate
	json.Unmarshal(pack[4:], &msg)
	return msg.Msg_id, msg.Date, nil
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值