(十一)TCP網絡編程小案例

1 要求

  • 1)編寫一個服務端程序,監聽8888端口
  • 2)可以和多個客戶端創建連接(goroutine)
  • 3)連接成功,客戶端可以發送數據,服務端接收數據,並顯示在終端上
  • 4)能通過終端輸入數據(一行一行發送),併發送給服務器
  • 5)在終端輸入exit,表示退出程序

2 C/S端處理流程

服務端的處理流程

  • 1)監聽端口 8888
  • 2)接收客戶端的tcp連接,建立客戶端和服務端的連接
  • 3)創建goroutine,處理該連接的請求(通常客戶端會通過連接發送請求包)

客戶端的處理流程

  • 1)建立與服務器端的連接
  • 2)發送請求數據,接收服務器端返回的結果數據
  • 3)關閉連接

要用到net包,官方文檔參考:

Go語言標準庫文檔中文版

3 代碼實現

3.1 Server端

package main

import (
	"fmt"
	"net"
)

func process(conn net.Conn)  {

	// 這裏我們循環的接收客戶端發送的數據
	defer conn.Close()  // 關閉連接

	for {
		// 創建一個切片,用於存放接收客戶端發送過來的數據
		buf := make([]byte, 1024)
		
		// 1.等待客戶端通過conn發送信息
		// 2.如果客戶端沒有write[發送],那麼協程就阻塞在這裏
		// fmt.Printf("服務器在等待客戶端%s 發送信息\n", conn.RemoteAddr().String())
		n, err := conn.Read(buf)  // 從conn讀取數據 Read接收測參數的是一個切片
		if err != nil {
			fmt.Printf("客戶端 %s 已退出.\n", conn.RemoteAddr().String())
			return
		}

		// 3.顯示客戶端發送了 %d 字節的數據
		fmt.Print(string(buf[:n]))  // 一定要把n給切片處理下,不然會出輸出很長的內容

	}

}

func main() {

	fmt.Println("服務器開始監聽...")

	listen, err := net.Listen("tcp", "0.0.0.0:8888")  // 在本地監聽8888端口
	if err != nil {
		fmt.Println("listen err = ", err)
		return
	}

	defer listen.Close()  // 關閉監聽端口

	// 循環等待客戶端接入
	for {
		// 等待客戶端連接
		fmt.Println("等待客戶端來連接...")
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("Accept() err=", err)
		} else {
			// 顯示客戶端ip conn.RemoteAddr().String()
			fmt.Printf("Client connected successfully, Client_IP = %v\n", conn.RemoteAddr().String())
		}
		
		// 這裏準備起一個協程,爲多個客戶端服務
		go process(conn)
	}
	fmt.Printf("listen suc= %v ", listen)
}

3.2 Client端

package main

import (
	"fmt"
	"net"
	"bufio"
	"os"
	"strings"
)

func main() {

	// 連接服務端

	conn, err := net.Dial("tcp", "127.0.0.1:8888")
	if err != nil {
		fmt.Printf("client dial failed err = %v", err)
		return
	}
	//fmt.Println("conn=", conn)

	// 客戶端往服務端發送單行數據,然後就退出
	// 客戶端在終端輸入一句話
	reader := bufio.NewReader(os.Stdin)  // os.Stdin 代表標準輸入,即終端

	for {
		// 從終端讀取一行用戶輸入,並準備發送給服務器
		line, err := reader.ReadString('\n')
		if err != nil {
			fmt.Println("readstring err = ", err)
		}

		// 如果用戶輸入的是exit就退出
		line = strings.Trim(line, " \r\n")
		if line == "exit" {
			fmt.Println("客戶端退出...")
			break
		}

		// 再將line 發送給服務器
		_, err = conn.Write([]byte(line + "\n"))
		if err != nil {
			fmt.Println("conn.Write err = ", err)
		}
	}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章