tcp解决粘包

代码链接: https://github.com/wjw1758548031/Golang/blob/master/tcp.go

tcp协议相对于udp协议的差别
TCP UDP
是否连接 面向连接 面向非连接
传输可靠性 可靠 不可靠
应用场合 少量数据 传输大量数据
速度 慢 快
根据这个确定运用场合就好。

tcp粘包原因:
tcp协议的优化导致而成,也就是在多少毫秒内需要等到多少大小的缓存内容,才会进行发送,在
高并发模式下,很容易造成这样的问题,也就会几个包的内容黏在一起,甚至一个包只粘了一半的
内容在上个包的结尾。

解决方式:
第一种:在客户端进行操作,强行发送或者是等待一个缓存的确认时间,一个个发送,但是这样
tcp的优化就没太大效果,不建议使用。
第二种:在服务端进行校验:
发送时 设置 body 以及 head
body:序列化内容
head:需要记录内容大小。
head的字节是需要固定好的,比如int64是最大容量8位字节,那么就记录8位字节,好让服务端获取。
此时设置好这些的话,服务端就能根据头部具体的取到自己的内容,然后再做些校验等操作。
文字讲的不够详细,实在不明,直接看代码,代码简洁明了。

package main

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"net"
	"time"
)

//int64 序列化最大容量为8
var (
	headLen  = int64(8)
	bodyByte = make([]byte, 0)
)

//tcp双项通道
func main() {
	go ServerBase()
	time.Sleep(1 * time.Second) //网速卡的话自己调整,可能在没创建完就已经连接
	go ClientBase()
	time.Sleep(1 * time.Hour)
}

func ServerBase() {
	fmt.Println("Starting the server...")
	//create listener
	listener, err := net.Listen("tcp", "127.0.0.1:50000")
	if err != nil {
		fmt.Println("Error listening:", err.Error())
		return
	}

	// listen and accept connections from clients:
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Error accepting:", err.Error())
			return
		}
		//create a goroutine for each request.
		go doServerStuff(conn)
	}

}

type TcpDate struct {
	Header int64
	Body   string
}

func NewTcpDate(Body string) TcpDate {
	return TcpDate{Header: int64(len(Body)), Body: Body}
}

func (t TcpDate) EncodeHeader() []byte {
	b_buf := new(bytes.Buffer)
	if err := binary.Write(b_buf, binary.BigEndian, &t.Header); err != nil {
		panic(err)
	}
	return b_buf.Bytes()
}

func (t TcpDate) Encode() []byte {
	return []byte(string(t.EncodeHeader()) + t.Body)
}

func (t *TcpDate) Decode(data []byte,  endLen int64) (bool, []byte) {
	if endLen > int64(len(data)-1){
		return false,data
	}
	head := data[:endLen]
	b_buf := new(bytes.Buffer)
	b_buf.Write(head)
	if err := binary.Read(b_buf, binary.BigEndian, &t.Header); err != nil {
		panic(err)
	}
	body := data[endLen : endLen+t.Header]
	t.Body = string(body)
	fmt.Println(t.Body)
	return true, data[endLen+t.Header:]
}

func doServerStuff(conn net.Conn) {
	fmt.Println("new connection:", conn.LocalAddr())
	for {
		data := TcpDate{}
		//自己定义长度,如果数据过多。。。。
		buf := make([]byte, 1024)
		bufLen, err := conn.Read(buf)
		if err != nil {
			fmt.Println("Error reading:", err.Error())
			return
		}
		bodyByte = []byte(fmt.Sprintf("%v%v",string(bodyByte) , string(buf[:bufLen])))
		for ; ; {
			var is bool
			is,bodyByte = data.Decode(bodyByte, headLen)
			if !is  {
				break
			}
		}
		/*len,_ := strconv.Atoi(strings.TrimPrefix(string(head),"ceshi:"))
		fmt.Println("data:",string(buf[100:len]))*/
		conn.Write([]byte("已收到"))

	}
}

func ClientBase() {
	//open connection:
	conn, err := net.Dial("tcp", "127.0.0.1:50000")
	if err != nil {
		fmt.Println("Error dial:", err.Error())
		return
	}
	//send info to server until Quit
	for i := 0; i < 100; i++ {
		go func() {
			item := struct {
				Name1 string
				Name2 string
				Name3 string
				Name4 string
				Name5 string
			}{}

			body, _ := json.Marshal(item)
			data := NewTcpDate(string(body))
			dataByte := data.Encode()
			_, err := conn.Write(dataByte)
			if err != nil {
				fmt.Println("Error Write:", err.Error())
				return
			}

			//这里就是简单的接收
			buf := make([]byte, 1024)
			length, err := conn.Read(buf)
			if err != nil {
				fmt.Println("Error reading:", err.Error())
				return
			}
			fmt.Println("Receive data from server:", string(buf[:length]))
		}()
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园悬赏任务平台对字典管理、论坛管理、任务资讯任务资讯公告管理、接取用户管理、任务管理、任务咨询管理、任务收藏管理、任务评价管理、任务订单管理、发布用户管理、管理员管理等进行集中化处理。经过前面自己查阅的网络知识,加上自己在学校课堂上学习的知识,决定开发系统选择小程序模式这种高效率的模式完成系统功能开发。这种模式让操作员基于浏览器的式进行网站访问,采用的主流的Java语言这种面向对象的语言进行校园悬赏任务平台程序的开发,在数据库的选择上面,选择功能强大的Mysql数据库进行数据的存放操作。校园悬赏任务平台的开发让用户查看任务信息变得容易,让管理员高效管理任务信息。 校园悬赏任务平台具有管理员角色,用户角色,这几个操作权限。 校园悬赏任务平台针对管理员设置的功能有:添加并管理各种类型信息,管理用户账户信息,管理任务信息,管理任务资讯公告信息等内容。 校园悬赏任务平台针对用户设置的功能有:查看并修改个人信息,查看任务信息,查看任务资讯公告信息等内容。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。项目管理页面提供的功能操作有:查看任务,删除任务操作,新增任务操作,修改任务操作。任务资讯公告信息管理页面提供的功能操作有:新增任务资讯公告,修改任务资讯公告,删除任务资讯公告操作。任务资讯公告类型管理页面显示所有任务资讯公告类型,在此页面既可以让管理员添加新的任务资讯公告信息类型,也能对已有的任务资讯公告类型信息执行编辑更新,失效的任务资讯公告类型信息也能让管理员快速删除。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值