天天看點

原生Golang 實作聊天室

伺服器端代碼:

package main

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

const LOG_DIRECTORY  =  "E:\\project\\mygo\\src\\chatRoom\\log.log"
var  onlineConns = make(map[string]net.Conn)
var messageQueue = make(chan string, 1000)
var quitChan  = make(chan bool)
var logger *log.Logger


func CheckError(err error)  {
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}
}

func ProcessInfo(conn net.Conn)  {
	buf := make([]byte, 1024)
	defer func(conn net.Conn) {
		addr := fmt.Sprintf("%s", conn.RemoteAddr())
		delete(onlineConns, addr)
		conn.Close()
		for i := range onlineConns {
			fmt.Println(i)
		}
	}(conn)

	for  {
		numOfBytes, err := conn.Read(buf)
		if err != nil {
			continue
		}
		if numOfBytes != 0 {
			message := string(buf[0:numOfBytes])
			messageQueue <- message
			//remoteAddr := conn.RemoteAddr()
			//fmt.Println(remoteAddr)
			//fmt.Printf("Has received this message:%s\n", string(buf[0:numOfBytes]))
		}
	}
}

func ConsumeMessage()  {
	for  {
		select {
		case message := <- messageQueue:
			//對消息進行解析
			doProcessMessage(message)
		case <- quitChan:
			break

		}
	}
}

func doProcessMessage(message string)  {
	contents := strings.Split(message, "#")
	if len(contents) > 1 {
		addr := contents[0]
		sendMessage := strings.Join(contents[1:], " ")
		addr = strings.Trim(addr, " ")
		if conn, ok := onlineConns[addr]; ok {
			_, err := conn.Write([]byte(sendMessage))
			if err != nil {
				fmt.Println("消息發送失敗!")
			}
		}
	}else {
		contents := strings.Split(message, "*")
		if strings.ToUpper(contents[1]) == "LIST" {
			var ips string = ""
			for i := range onlineConns{
				ips = ips + "|" + i
			}
			if conn, ok := onlineConns[contents[0]]; ok {
				_, err := conn.Write([]byte(ips))
				if err != nil {
					fmt.Println("消息發送失敗!")
				}
			}
		}

	}
}

func main()  {
	logFile, err := os.OpenFile(LOG_DIRECTORY, os.O_RDWR|os.O_CREATE, 0)
	if err != nil {
		fmt.Println("log File 建立失敗!")
		os.Exit(-1)
	}
	defer logFile.Close()
	logger = log.New(logFile, "\r\n", log.Ldate|log.Ltime|log.Llongfile)
	listen_socket, err := net.Listen("tcp", "127.0.0.1:8900")
	CheckError(err)
	defer listen_socket.Close()
	fmt.Println("聊天室已經開始運作!\n")
	logger.Println("寫入日志!")

	go ConsumeMessage()

	for {
		conn, err := listen_socket.Accept()
		CheckError(err)
		addr := fmt.Sprintf("%s", conn.RemoteAddr())
		onlineConns[addr] =conn
		for i := range onlineConns {
			fmt.Println(i)
		}
		go ProcessInfo(conn)
	}
	
}
           

用戶端代碼:

package main

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

func CheckError(err error) {
	if err != nil {
		fmt.Printf("s%", err)
		os.Exit(1)
	}

}

func MessageSend(conn net.Conn)  {
	var input string
	for   {
		reader := bufio.NewReader(os.Stdin)
		data, _ , _ := reader.ReadLine()
		input = string(data)
		//fmt.Println(strings.ToUpper(input))
		if strings.ToUpper(input) == "EXIT" {
			fmt.Println("關閉連接配接")
			conn.Close()
			break
		}

		_, err := conn.Write([]byte(input))
		if err != nil {
			conn.Close()
			fmt.Println("用戶端連接配接錯誤:"+err.Error())
			break
		}
	}
}


func main()  {
	conn, err := net.Dial("tcp", "127.0.0.1:8900")
	CheckError(err)
	defer conn.Close()
	//conn.Write([]byte("Hello Golang!"))
	go MessageSend(conn)
	buf := make([]byte, 1024)
	for  {
		length, err := conn.Read(buf)
		if err != nil {
			fmt.Println("您已退出!")
			os.Exit(0)
		}
		if length != 0 {
			CheckError(err)
			fmt.Println("收到消息,消息内容:"+ string(buf))
		}

	}

	fmt.Print("消息已經發送!")

}