go語言聊天室

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
)
/**
主程序  啓動客戶端和服務端
參數說明:
  啓動服務器端:  go run main.go server [port]             eg: go run main.go server 9090
  啓動客戶端:   go run main.go [Server Ip Addr]:[Server Port]    eg: go run main.go client :9090
 */
func main()  {
	if len(os.Args) != 3 {
		fmt.Println("wrong params")
		os.Exit(0)
	}
	if os.Args[1] == "server" {
		StartServer(os.Args[2])
	}
	if os.Args[1] == "client" {
		StartClient(os.Args[2])
	}
}

/**
啓動服務器
參數:port 端口號
 */
func StartServer(port string)  {
	service := ":" + port
	tcpAddr,err := net.ResolveTCPAddr("tcp4", service)
	checkError(err, "ResolveTCPAddr")
	l,err := net.ListenTCP("tcp", tcpAddr)
	checkError(err ,"ListenTCP")
	conns := make(map[string]net.Conn)
	messages := make(chan string, 10)

	//啓動服務器廣播線程 :向所有客戶端發送消息
	go echoHandler(&conns, messages)

	for {
		fmt.Println("Listening ...")
		conn,err := l.Accept()//返回一個新的連接
		checkError(err , "l.Accept")
		fmt.Println("Accepting ...")
		conns[conn.RemoteAddr().String()] = conn
		//啓動一個接受客戶端發送消息的線程
		go Handler(conn, messages)
	}
}
/**
服務器發送數據的線程:向所有客戶端發送消息
參數
   連接字典 conns
   數據通道 messages
 */
func echoHandler(conns *map[string]net.Conn, messages chan string)  {
	for {
		//向通道中傳入數據
		msg := <-messages
		fmt.Println(msg)

		for key,con := range *conns {
			fmt.Println("connection is connected from ...", key)
			_,err := con.Write([]byte(msg))
			if err != nil {
				fmt.Println(err)
				delete(*conns, key)
			}
		}

	}
}

/**
服務器端接收客戶端數據線程
參數:
    據連接 conn
    通訊通道 messages
 */
func Handler(conn net.Conn, messages chan string)  {
	fmt.Println("connection is connected from ...", conn.RemoteAddr().String())

	buf := make([]byte, 1024)
	for {
		lenght,err := conn.Read(buf)
		if checkError(err, "Connection") == false {
			conn.Close()
			break
		}
		if lenght >0 {
			buf[lenght] = 0
		}
		reciveStr := string(buf[0:lenght])
		messages <- reciveStr
	}
}

/**
客戶端啓動函數
參數:
    程ip地址和端口 tcpaddr
 */
func StartClient(tcpaddr string)  {
	tcpAddr,err := net.ResolveTCPAddr("tcp4", tcpaddr)
	checkError(err, "ResolveTCPAddr")
	conn,err := net.DialTCP("tcp",nil,tcpAddr)
	checkError(err, "DialTCP")

	//啓動客戶端發送數據線程
	go chatSend(conn)

	//接收服務端發送來的消息
	buf := make([]byte, 1024)
	for {
		lenght,err := conn.Read(buf)
		if checkError(err, "Connection") == false {
			conn.Close()
			fmt.Println("Server is dead ...ByeBye")
			os.Exit(0)
		}
		fmt.Println(string(buf[0:lenght]))
	}
}

/**
客戶端發送數據線程
參數:
     發送連接 conn
 */
func chatSend(conn net.Conn)  {
	//var input string
	username := conn.LocalAddr().String()
	inputReader := bufio.NewReader(os.Stdin)
	index := 0
	for {
		//fmt.Scanln(&input)
		//這個地方改爲回車結束判斷,利用上面的輸入檢測,會有問題(不知道如何表述,就是會出現錯亂)
		input, err := inputReader.ReadString('\n')
		//fmt.Fscan(stdin, &input)
		if input == "/quit" {
			fmt.Println("ByeBye..")
			conn.Close()
			os.Exit(0)
		}
		lens,err := conn.Write([]byte(username + "say ::: " + input))
		//這個地方lens不能缺省,不知道爲什麼
		if lens == 0 {
			//
		}
		if err != nil {
			fmt.Println(err.Error())
			conn.Close()
		}
		index++
	}
}

//錯誤信息
func checkError(err error, info string)  (res bool) {
	if err != nil {
		fmt.Println(info + ",err:" + err.Error())
		return false
	}
	return true
}

這個是自己做了一點修改,如果是原版的方法,客戶端在字符串中添加空格的時候,那個方法scanln會自動分割空格兩端的字符串,從而錯亂,所以改了這個版本(就是客戶端在想服務端的通道出入數據的時候的一點修改),初學炸到,不喜勿噴

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