基于Go分别在两台虚拟机上使用TCP和KCP传输一张图片的demo
TCP传输
TCP服务端
使用服务端接收图片,此虚拟机的ip是192.168.10.107
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| package main
import ( "bytes" "fmt" "io" "net" "os" "time" )
func main() { lis, err := net.Listen("tcp", "192.168.10.107:10000") if err != nil { fmt.Printf("Error connecting to server: %s\n", err) return } defer lis.Close()
file, err := os.Create("received_image.png") if err != nil { fmt.Printf("Error creating file: %s\n", err) return } defer file.Close()
buffer := make([]byte, 1024*256) endSignal := []byte("TRANSFER_COMPLETED")
startTime := time.Now()
conn, err := lis.Accept() if err != nil { panic(err) } defer conn.Close()
fmt.Println(time.Now())
for { n, err := conn.Read(buffer) if err != nil { if err == io.EOF { break } fmt.Printf("Error reading data: %s\n", err) return }
if bytes.Equal(buffer[:n], endSignal) { break }
_, err = file.Write(buffer[:n]) if err != nil { fmt.Printf("Error writing to file: %s\n", err) return }
}
endTime := time.Now() elapsedTime := endTime.Sub(startTime) print(elapsedTime.Milliseconds())
fileInfo, err := file.Stat() if err != nil { fmt.Printf("Error getting file info: %s\n", err) return } fileSize := fileInfo.Size() fmt.Println(fileSize)
transferSpeed := float64(fileSize) / float64((elapsedTime.Milliseconds() * (1024 * 1024))/1000)
fmt.Printf("File transfer complete. Transfer speed: %.2f MB/s\n", transferSpeed)
}
|
收起代码
首先监听本地ip和相应端口,获取一个listener,通过listener的Accept方法后就可以获取一个连接,通过连接便可传送数据。先创建一个空文件和缓冲区,进入循环,循环中将连接的数据写入到缓冲区中,获取得到的字节数n,并将数据写入到本地文件,直到遇到传输结束信号”TRANSFER_COMPLETED”
TCP客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package main
import ( "fmt" "io" "log" "net" "os" "time" )
func main() { conn, err := net.Dial("tcp", "192.168.10.107:10000") if err!= nil { fmt.Println(err) } defer conn.Close() if err != nil { log.Fatal("Listen failed:", err) }
fmt.Println("Server started, waiting for connections...")
handleClientWithTCP(conn) }
func handleClientWithTCP(conn net.Conn) {
file, err := os.Open("mountain.png") if err != nil { log.Fatal("Create file failed:", err) } defer file.Close()
buf := make([]byte, 1024*256)
for { n, err := file.Read(buf) if err != nil { if err != io.EOF { log.Println("Read from file failed:", err) } break }
_, err = conn.Write(buf[:n]) if err != nil { log.Println("Write to client failed:", err) break } }
_, err = conn.Write([]byte("TRANSFER_COMPLETED")) if err != nil { fmt.Printf("Error sending completion signal: %s\n", err) return } fmt.Println(time.Now()) fmt.Println("Image transfer completed.") }
|
收起代码
获取到连接conn后,循环将文件数据file写入到缓冲区中,然后将缓冲区的数据发送到连接中,直到遇到io.EOF跳出循环,发送了结束标志
KCP传输
KCP服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| package main
import ( "bytes" "fmt" "github.com/xtaci/kcp-go" "io" "net" "os" "time" )
const ( serverAddr = "192.168.10.107:10000" )
func kcpRecv() { lis, err := kcp.ListenWithOptions(serverAddr, nil, 10, 3) if err != nil { fmt.Printf("Error connecting to server: %s\n", err) return } defer lis.Close()
file, err := os.Create("received_image.png") if err != nil { fmt.Printf("Error creating file: %s\n", err) return } defer file.Close()
buffer := make([]byte, 1024*256) endSignal := []byte("TRANSFER_COMPLETED")
startTime := time.Now()
conn, err := lis.AcceptKCP() if err != nil { panic(err) } defer conn.Close()
fmt.Println(time.Now())
for { n, err := conn.Read(buffer) if err != nil { if err == io.EOF { break } fmt.Printf("Error reading data: %s\n", err) return }
if bytes.Equal(buffer[:n], endSignal) { break }
_, err = file.Write(buffer[:n]) if err != nil { fmt.Printf("Error writing to file: %s\n", err) return }
}
endTime := time.Now() elapsedTime := endTime.Sub(startTime)
fileInfo, err := file.Stat() if err != nil { fmt.Printf("Error getting file info: %s\n", err) return } fileSize := fileInfo.Size()
transferSpeed := float64(fileSize) / elapsedTime.Seconds() / (1024 * 1024)
fmt.Printf("File transfer complete. Transfer speed: %.2f MB/s\n", transferSpeed)
}
|
收起代码
kcp-go与tcp的接口做了兼容处理,可以无障碍替换使用tcp,也增加了一些可选项,如前向纠错,如kcp.ListenWithOptions(serverAddr, nil, 10, 3)的10和3就代表着每发送10个包就发送3个冗余包
KCP客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package main
import ( "time" "fmt" "log" "os" "io" "github.com/xtaci/kcp-go" )
const ( serverAddr = "192.168.10.107:10000" )
func kcpSend() { conn, err := kcp.DialWithOptions(serverAddr, nil, 10, 3) if err!= nil { fmt.Println(err) } defer conn.Close() if err != nil { log.Fatal("Listen failed:", err) }
fmt.Println("Server started, waiting for connections...")
handleClient(conn) }
func handleClient(conn *kcp.UDPSession) {
file, err := os.Open("mountain.png") if err != nil { log.Fatal("Create file failed:", err) } defer file.Close()
buf := make([]byte, 1024*256)
for { n, err := file.Read(buf) if err != nil { if err != io.EOF { log.Println("Read from file failed:", err) } break }
_, err = conn.Write(buf[:n]) if err != nil { log.Println("Write to client failed:", err) break } }
_, err = conn.Write([]byte("TRANSFER_COMPLETED")) if err != nil { fmt.Printf("Error sending completion signal: %s\n", err) return }
fmt.Println(time.Now()) fmt.Println("Image transfer completed.") }
|
收起代码