天天看點

Golang網絡程式設計實作TCP-CS網絡檔案傳輸

文章目錄

      • 網絡檔案傳輸:
      • 檔案傳輸——發送端(用戶端):
      • 檔案傳輸——接收端(伺服器):

網絡檔案傳輸:

指令行參數: 在main函數啟動時,向整個程式傳參。

	文法: go run xxx.go	  argv1 argv2  argv3  argv4

		xxx.go:  第 0 個參數。
		argv1 :第 1 個參數。
		argv2 :第 2個參數。	
		argv3 :第 3 個參數。
		argv4 :第 4 個參數。

	使用: list := os.Args

	          參數3 = list[3]

擷取檔案屬性:

	fileInfo:os.stat(檔案通路絕對路徑)

	fileInfo 接口,兩個接口。

		 Name() 擷取檔案名。

		 Size() 擷取檔案大小。
           
func main()  {
	list := os.Args			// 擷取指令行參數

	if len(list) != 2 {
		fmt.Println("格式為:go run xxx.go 檔案名")
		return
	}
	// 提取檔案名
	path := list[1]
	// 擷取檔案屬性
	fileInfo, err := os.Stat(path)
	if err != nil {
		fmt.Println("os.Stat err:", err)
		return
	}
	fmt.Println("檔案名:", fileInfo.Name())
	fmt.Println("檔案大小:", fileInfo.Size())
}
           

檔案傳輸——發送端(用戶端):

1. 提示使用者使用指令行參數輸入檔案名。接收檔案名 filepath(含通路路徑)

2. 使用 os.Stat()擷取檔案屬性,得到純檔案名 fileName(去除通路路徑)

3. 主動發起連接配接伺服器請求,結束時關閉連接配接。

4. 發送檔案名到接收端 conn.Write()

5. 讀取接收端回發的确認資料 conn.Read()

6. 判斷是否為“ok”。如果是,封裝函數 SendFile() 發送檔案内容。傳參 filePath 和 conn

7. 隻讀 Open 檔案, 結束時Close檔案

8. 循環讀本地檔案,讀到 EOF,讀取完畢。

9. 将讀到的内容原封不動 conn.Write 給接收端(伺服器)
           
func sendFile(conn net.Conn, filePath string)  {
	// 隻讀打開檔案
	f, err := os.Open(filePath)
	if err != nil {
		fmt.Println("os.Open err:", err)
		return
	}
	defer f.Close()

	// 從本檔案中,讀資料,寫給網絡接收端。 讀多少,寫多少。原封不動。
	buf := make([]byte, 4096)
	for {
		n, err := f.Read(buf)
		if err != nil {
			if err == io.EOF {
				fmt.Println("發送檔案完成。")
			} else {
				fmt.Println("os.Open err:", err)
			}
			return
		}
		// 寫到網絡socket中
		_, err = conn.Write(buf[:n])
		if err != nil {
			fmt.Println("conn.Write err:", err)
			return
		}
	}
}

func main()  {
	list := os.Args		// 擷取指令行參數

	if len(list) != 2 {
		fmt.Println("格式為:go run xxx.go 檔案絕對路徑")
		return
	}
	// 提取 檔案的絕對路徑
	filePath := list[1]

	//提取檔案名
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		fmt.Println("os.Stat err:", err)
		return
	}
	fileName := fileInfo.Name()

	// 主動發起連接配接請求
	conn, err := net.Dial("tcp", "127.0.0.1:8008")
	if err != nil {
		fmt.Println("net.Dial err:", err)
		return
	}
	defer conn.Close()

	// 發送檔案名給 接收端
	_, err = conn.Write([]byte(fileName))
	if err != nil {
		fmt.Println("conn.Write err:", err)
		return
	}
	// 讀取伺服器回發的 OK
	buf := make([]byte, 16)
	n, err := conn.Read(buf)
	if err != nil {
		fmt.Println("conn.Read err:", err)
		return
	}

	if "ok" == string(buf[:n]) {
		// 寫檔案内容給伺服器——借助conn
		sendFile(conn, filePath)
	}
}
           

檔案傳輸——接收端(伺服器):

1. 建立監聽 listener,程式結束時關閉。

2. 阻塞等待用戶端連接配接 conn,程式結束時關閉conn。

3. 讀取用戶端發送檔案名。儲存 fileName。

4. 回發“ok”。

5. 封裝函數 RecvFile 接收用戶端發送的檔案内容。傳參 fileName 和 conn

6. 按檔案名 Create 檔案,結束時 Close

7. 循環 Read 發送端網絡檔案内容,當讀到 0 說明檔案讀取完畢。

8. 将讀到的内容原封不動Write到建立的檔案中
           
func recvFile(conn net.Conn, fileName string)  {
	// 按照檔案名建立新檔案
	f, err := os.Create(fileName)
	if err != nil {
		fmt.Println("os.Create err:", err)
		return
	}
	defer f.Close()

	// 從 網絡中讀資料,寫入本地檔案
	buf := make([]byte, 4096)
	for {
		n,_ := conn.Read(buf)
		if n == 0 {
			fmt.Println("接收檔案完成。")
			return
		}
		// 寫入本地檔案,讀多少,寫多少。
		f.Write(buf[:n])
	}
}

func main()  {
	// 建立用于監聽的socket
	listener, err := net.Listen("tcp", "127.0.0.1:8008")
	if err != nil {
		fmt.Println(" net.Listen err:", err)
		return
	}
	defer listener.Close()

	// 阻塞監聽
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println(" listener.Accept() err:", err)
		return
	}
	defer conn.Close()

	// 擷取檔案名,儲存
	buf := make([]byte, 4096)
	n, err := conn.Read(buf)
	if err != nil {
		fmt.Println(" conn.Read err:", err)
		return
	}
	fileName := string(buf[:n])

	// 回寫 ok 給發送端
	conn.Write([]byte("ok"))

	// 擷取檔案内容
	recvFile(conn, fileName)
}
           

繼續閱讀