Golang加头和尾部来解决tcp粘包问题.代码片段示例

package main

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"io"
	"net"
)

var empty []byte

func main() {
	lis, _ := net.Listen("tcp", ":1789")
	for {
		con, err := lis.Accept()
		if err != nil {
			continue
		}
		//当建立连接的时候交给registerConn来处理这个链接.
		//想自定义就可以把这个函数重写.
		go registerConn(con)
	}
}

type ConnectionInfo struct {
	Conn     net.Conn
	Buf      *bufio.Reader
	Authfunc func(msg []byte) bool
}

type ConnResolve interface {
	OnceRead() ([]byte, error)
	StillRead()
	Close() error
	AuthFuncation(msg []byte) bool
}

func (self *ConnectionInfo) OnceRead() ([]byte, error) {
	return reader(self.Buf)
}

func (self *ConnectionInfo) AuthFuncation(msg []byte) bool {
	return self.Authfunc(msg)
}

func (self *ConnectionInfo) Close() error {
	return self.Conn.Close()
}

func (self *ConnectionInfo) StillRead() {
	for {
		msg, err := reader(self.Buf)
		if err != nil {
			if err == io.EOF {
				continue
			}
			return
		}
		fmt.Printf("收到的信息: %s\n", string(msg))
	}
}

func registerConn(conn net.Conn) {
	defer conn.Close()
	//这里返回的是一个接口,可以自定义消息处理机制.
	reg := NewconnectionInfo(conn, nil)
	//接入的时候第一次读取认证信息,然后
	msg, err := reg.OnceRead()
	if err != nil {
		return
	}
	if !reg.AuthFuncation(msg) {
		return
	}
	reg.StillRead()
}

func NewconnectionInfo(conn net.Conn, authfunc func(msg []byte) bool) ConnResolve {
	if authfunc == nil {
		authfunc = DefaultAuthFunc
	}
	return &ConnectionInfo{conn, bufio.NewReader(conn), authfunc}
}

func DefaultAuthFunc(msg []byte) bool {
	fmt.Println("开始校验认证信息: ", string(msg))
	return true
}

//reader方法是用来定义读取的流的逻辑的,可以自己按找自己的逻辑定义.
func reader(buf *bufio.Reader) ([]byte, error) {
	head := make([]byte, 5)
	_, err := buf.Read(head)
	if err != nil {
		return empty, err
	}
	bodyLen, _ := binary.Uvarint(head)
	line, err := buf.ReadSlice('\n')
	if err != nil {
		return empty, err
	}
	if uint64(len(line)-1) != bodyLen {
		return empty, io.EOF
	}
	return line[:bodyLen], nil
}
func writer(conn net.Conn, msg []byte) (int, error) {
	mgslen := len(msg)
	head := make([]byte, 5+mgslen+1)
	binary.PutUvarint(head, uint64(mgslen))
	copy(head[5:], msg)
	head[mgslen] = '\n'
	return conn.Write(head)
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Go语言使用TCP实现大文件传输的示例代码如下:package mainimport ( "fmt" "net" "os" )// 检查错误 func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) os.Exit(1) } }func main() { // 创建套接字 conn, err := net.Dial("tcp", "127.0.0.1:8080") checkError(err) // 打开文件 f, err := os.Open("example.txt") checkError(err) // 读取文件 buf := make([]byte, 1024) for { n, err := f.Read(buf) if err != nil && err != io.EOF { fmt.Println("Read file error:", err) return } if n == 0 { fmt.Println("Transfer success!") return } _, err = conn.Write(buf[:n]) if err != nil { fmt.Println("Write Error:", err) return } } } ### 回答2: 下面是使用Golang语言通过TCP实现大文件传输的示例代码: ```go package main import ( "fmt" "io" "net" "os" ) func main() { // 服务器IP和端口 serverIP := "127.0.0.1" serverPort := "8080" // 本地文件路径 filePath := "example.txt" // 连接服务器 conn, err := net.Dial("tcp", serverIP+":"+serverPort) if err != nil { fmt.Println("连接服务器失败:", err) return } defer conn.Close() // 打开本地文件 file, err := os.Open(filePath) if err != nil { fmt.Println("打开文件失败:", err) return } defer file.Close() // 读取文件内容并写入网络连接 buffer := make([]byte, 1024) for { // 从文件读取内容 n, err := file.Read(buffer) if err != nil && err != io.EOF { fmt.Println("读取文件失败:", err) return } // 写入网络连接 _, err = conn.Write(buffer[:n]) if err != nil { fmt.Println("发送文件内容失败:", err) return } // 文件读取结束退出循环 if err == io.EOF { break } } fmt.Println("文件传输完成") } ``` 该示例代码中,使用`net.Dial()`函数连接到指定的服务器IP和端口。然后,通过`os.Open()`函数打开本地文件,并逐步读取文件内容,使用`conn.Write()`函数将读取到的内容写入到TCP连接中,实现文件传输。最后,使用`fmt.Println()`输出文件传输完成的提示信息。 注意:该示例代码仅包含文件传输的基本功能,对于大文件传输,还需要处理断点续传和传输过程中的错误处理等问题。 ### 回答3: 首先,我们需要使用Go语言的标准库中的"net"和"io"包来实现TCP连接和文件传输。 下面是一个使用Go语言实现TCP传输大文件的示例代码: ```go package main import ( "fmt" "io" "net" "os" ) func main() { // 监听的地址和端口 address := "localhost:8080" // 打开待传输的文件 file, err := os.Open("large_file.txt") if err != nil { fmt.Println("无法打开文件:", err) return } defer file.Close() // 创建TCP连接 conn, err := net.Dial("tcp", address) if err != nil { fmt.Println("无法建立TCP连接:", err) return } defer conn.Close() // 复制文件数据到连接中 _, err = io.Copy(conn, file) if err != nil { fmt.Println("无法复制文件到连接:", err) return } fmt.Println("文件传输完成") } ``` 在上面的示例中,我们首先打开待传输的大文件"large_file.txt",然后创建TCP连接并将文件数据复制到连接中。 你可以将以上代码保存到一个.go文件中,并使用go run命令来运行程序。在示例代码中,请确保将"large_file.txt"替换为你想要传输的实际文件名,以及将"localhost:8080"替换为实际的目标地址和端口。 这段示例代码会将文件内容从客户端传输到服务器端。你可以根据需要修改代码,以实现文件的双向传输或其他相关的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值