1. 程式人生 > >網路通訊4:TCP廣播

網路通訊4:TCP廣播

服務端實現

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

//儲存客戶端連線, key,ip埠,value 連結物件
var onlineConnsMap = make(map[string]net.Conn)

//訊息佇列,緩衝區
var messageQueue = make(chan string, 1000)

//訊息,處理程式退出
var quitchan = make(chan bool)

func CheckErrorS(err error) {
	if err != nil {
		fmt.Println("網路錯誤", err.Error())
		os.Exit(1)
	}
}

func Processinfo(conn net.Conn) {
	buf := make([]byte, 1024) //開創緩衝區
	defer func() {
		//關閉連線
		conn.Close()
		fmt.Println("連線已關閉:",conn.RemoteAddr())
	}()

	for {
		n, err := conn.Read(buf) //讀取資料
		if err != nil {
			fmt.Println("讀取客戶端訊息出錯,err=",err)
			break
		}

		if n != 0 {
			//訊息處理,
			message := string(buf[0:n])
			fmt.Printf("受到客戶端%v訊息:%s\n",conn.RemoteAddr(),message)

			//訊息佇列儲存訊息
			messageQueue <- message
			fmt.Println("該條訊息已加入佇列...")

		}else{
			fmt.Println("讀取客戶端訊息長度為0")
		}
	}

}

//訊息的協程
func consumeMessage() {
	for {
		select {
		case message := <-messageQueue: //取出訊息
			fmt.Println("已從佇列中取出訊息")
			strs := strings.Split(message, "#") //字串切割
			if len(strs) > 1 {

				//127.0.0.1:12345#去死

				//擷取地址並裁減頭尾空白
				addr := strs[0]
				addr = strings.TrimSpace(addr)

				//擷取內容
				msg := strs[1]

				//給所有客戶端群發此訊息
				/*for addr, conn := range onlineConnsMap { //迴圈線上列表
					_, err := conn.Write([]byte(msg))
					fmt.Println("伺服器傳送訊息", msg, "給", addr)
					if err != nil {
						fmt.Println("線上連結傳送失敗")
					}
				}*/

				//@某人,發訊息
				if conn, ok := onlineConnsMap[addr]; ok {
					_, err := conn.Write([]byte(msg))
					fmt.Println("伺服器傳送訊息", msg)
					if err != nil {
						fmt.Println("線上連結傳送失敗")
					}
				}


			}
		case <-quitchan: //處理退出
			os.Exit(0)
		}
	}
}

func main() {
	//建立TCP伺服器
	listener, err := net.Listen("tcp", "127.0.0.1:8898")
	CheckErrorS(err)
	defer listener.Close() //關閉網路

	fmt.Println("伺服器正在等待")

	go consumeMessage()

	for {
		conn, err := listener.Accept() //新的客戶端連線
		CheckErrorS(err)

		//處理每一個客戶端
		addr := fmt.Sprint(conn.RemoteAddr()) //取出地址
		onlineConnsMap[addr] = conn

		fmt.Println("客戶端列表")
		fmt.Println("-------------------")
		for key := range onlineConnsMap { //迴圈每一個連結
			fmt.Println(key)
		}

		go Processinfo(conn)
	}

}

客戶端呢實現

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

func CheckErrorC(err error) {
	if err != nil {
		fmt.Println("網路錯誤", err.Error())
	}
}

func MessageSend(conn net.Conn) {
	var input string
	for {
		reader := bufio.NewReader(os.Stdin) //讀取鍵盤輸入
		data, _, _ := reader.ReadLine()     //讀取一行
		input = string(data)                //鍵盤輸入轉化為字串

		if input == "exit" {
			conn.Close()
			fmt.Println("客戶端關閉")
			break
		}

		_, err := conn.Write([]byte(input)) //輸入寫入字串
		fmt.Println("傳送訊息", input)
		if err != nil {
			conn.Close()
			fmt.Println("客戶端關閉")
			break
		}

	}
}

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8898") //建立TCP伺服器
	defer conn.Close()                             //延遲關閉網路連線
	CheckErrorC(err)                               //檢查錯誤

	go MessageSend(conn)                           //開啟一個協程,處理髮送
	//conn.Write([]byte("hello  nimei"))

	//協程,負責收取訊息
	buf := make([]byte, 1024)
	for {
		numOfBytes, err := conn.Read(buf)
		CheckErrorC(err)
		fmt.Println("收到伺服器訊息", string(buf[:numOfBytes]))
	}

	fmt.Println("客戶端關閉")

}