Go language network communication --- tcp upload large files (sticky packet problem needs to be elegantly resolved)

Server side:

package main

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"net"
	"os"
	"unsafe"
)

func SHandleError(err error, when string)  {
	if err != nil{
		fmt.Println("服务端异常退出,err=", err, when)
		os.Exit(1)
	}
}

func BytesToInt64(buf []byte) int64 {
	return int64(binary.BigEndian.Uint64(buf))
}

func main() {
	//建立tcp监听
	listener, e := net.Listen("tcp", ":8080")
	SHandleError(e, "net.Listen")
	defer func() {
		listener.Close()
		fmt.Println("服务端正常退出") 
	// Accept the client request, establish a session dedicated line Conn
	} ()

	conn, e: = listener.Accept () 
	SHandleError (e, "listener.Accept") 
	defer func () { 
		conn.Close () 
		fmt.Printf ("The link with% v has been disconnected \ n", conn.RemoteAddr ()) 
	} () 

	dstFile, e: = os.OpenFile (`meinv1.mp4`, os.O_CREATE | os.O_WRONLY | os.O_TRUNC, 0666) 
	writer: = bufio.NewWriter (dstFile) 
	defer dstFile.Close () 
	buffer: = make ([] byte, 100) 
	total: = 0 

	// Accept the size of the file to be sent from the client 
	buffer2: = make ([] byte, 10) 
	m, e: = conn.Read (buffer2) 
	/ / size: = string (buffer2 [: m]) 
	//fmt.Printf("%s\n",size) 
	// i, _: = strconv.Atoi (size) 

	// [] byte converted to int64 
	i: = BytesToInt64 (buffer2 [: m]) 
	fmt.Printf ("% d,% T \ n", i, i)
	// int64 converted to int 
	j: = * (* int) (unsafe.Pointer (& i)) 
	fmt.Printf ("% d,% T \ n", j, j) 

	for { 
		// accept files uploaded by the client 
		n, e: = conn.Read (buffer) 
		SHandleError (e, "conn.Read") 
		total + = n 

		// Write to the server local file 
		writer.Write (buffer [: n]) 
		writer.Flush () 

		fmt. Printf ("Successfully written% d bytes, a total of% d bytes \ n", n, total) 

		// If the actual total number of received bytes is equal to the number of bytes to be transmitted by the client, it means the transmission is completed 
		if total == j { 
			fmt.Println ("File accepted successfully, total", total, "byte") 
			// Responded that the client has received the file 
			conn.Write ([] byte ("File accepted successfully")) 
			break 
		} 
	} 
}

client side:

package main

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

/*
·实现tcp文件上传功能
*/

func CHandleError2(err error, when string) {
	if err != nil {
		fmt.Println("客户端异常退出:err=", err, when)
		os.Exit(1)
	}
}
func Int64ToBytes(i int64) []byte {
	var buf = make([]byte, 8)
	binary.BigEndian.PutUint64(buf, uint64(i))
	return buf
}
func main() {
	conn, e := net.Dial("tcp", "127.0.0.1:8080")
	CHandleError2(e, "net.Dial") 
		fmt.Println ("Client exits normally")

	defer func () {
		conn.Close()
	} () 

	// Get the size of the target file and pass it to the server 
	fileInfo, _: = os.Stat (`perfect.mp4`) 
	size: = fileInfo.Size () 
	bytes: = Int64ToBytes (size) 
	conn.Write (bytes ) 

	// Temporarily solve the sticky packet problem through the client ’s sleep 200 milliseconds, and can also be resolved through tcp reconnection. Later, use (packet header + data) to encapsulate the data packet. 
	Time.Sleep (time.Millisecond * 200) 

	buffer: = make ([] byte, 100) 
	srcFile, _: = os.Open (`perfect.mp4`) 
	reader: = bufio.NewReader (srcFile) 
	total: = 0 
	for { 
		n, err: = reader.Read (buffer) 
		fmt .Println (n, err) 
		if err == io.EOF { 
			fmt.Println ("File sent completed") 
			fmt.Println (total) 
			break 
		} else {  
			_, e = conn.Write (buffer [: n])
			total + = n 
			CHandleError2 (e, "conn.Write") 
		}
	}

	n, e := conn.Read(buffer)
	CHandleError2(e, "conn.Read")
	replyMsg := buffer[:n]
	fmt.Println("服务端:", string(replyMsg))
}

  

Guess you like

Origin www.cnblogs.com/yunweiqiang/p/12735452.html