golang聊天室

golang對併發的支持很是好,就是由於他有一個goroutine機制和channel機制,實現併發場景輕鬆高效。python

下面咱們實現一個聊天室程序,代碼很少,可是功能很強大golang

//代碼轉載自:http://blog.csdn.net/ygrx/article/details/11773151
package main

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

////////////////////////////////////////////////////////
//
//錯誤檢查
//
////////////////////////////////////////////////////////
func checkError(err error, info string) (res bool) {

	if err != nil {
		fmt.Println(info + "  " + err.Error())
		return false
	}
	return true
}

////////////////////////////////////////////////////////
//
//服務器端接收數據線程
//參數:
//		數據鏈接 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
		}
		//fmt.Println("Rec[",conn.RemoteAddr().String(),"] Say :" ,string(buf[0:lenght]))
		reciveStr := string(buf[0:lenght])
		messages <- reciveStr

	}

}

////////////////////////////////////////////////////////
//
//服務器發送數據的線程
//
//參數
//		鏈接字典 conns
//		數據通道 messages
//
////////////////////////////////////////////////////////
func echoHandler(conns *map[string]net.Conn, messages chan string) {

	for {
		msg := <-messages
		fmt.Println(msg)

		for key, value := range *conns {

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

		}
	}

}

////////////////////////////////////////////////////////
//
//啓動服務器
//參數
//	端口 port
//
////////////////////////////////////////////////////////
func StartServer(port string) {
	service := ":" + port //strconv.Itoa(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, "Accept")
		fmt.Println("Accepting ...")
		conns[conn.RemoteAddr().String()] = conn
		//啓動一個新線程
		go Handler(conn, messages)

	}

}

////////////////////////////////////////////////////////
//
//客戶端發送線程
//參數
//		發送鏈接 conn
//
////////////////////////////////////////////////////////
func chatSend(conn net.Conn) {

	var input string
	username := conn.LocalAddr().String()
	for {

		fmt.Scanln(&input)
		if input == "/quit" {
			fmt.Println("ByeBye..")
			conn.Close()
			os.Exit(0)
		}

		lens, err := conn.Write([]byte(username + " Say :::" + input))
		fmt.Println(lens)
		if err != nil {
			fmt.Println(err.Error())
			conn.Close()
			break
		}

	}

}

////////////////////////////////////////////////////////
//
//客戶端啓動函數
//參數
//		遠程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]))

	}
}

////////////////////////////////////////////////////////
//
//主程序
//
//參數說明:
//	啓動服務器端:  Chat server [port]				eg: Chat server 9090
//	啓動客戶端:    Chat client [Server Ip Addr]:[Server Port]  	eg: Chat client 192.168.0.74:9090
//
////////////////////////////////////////////////////////
func main() {

	fmt.Println(os.Args)

	if len(os.Args) != 3 {
		fmt.Println("Wrong pare")
		os.Exit(0)
	}

	if os.Args[1] == "server" && len(os.Args) == 3 {

		StartServer(os.Args[2])
	}

	if os.Args[1] == "client" && len(os.Args) == 3 {

		StartClient(os.Args[2])
	}

}

只須要在命令行輸入例如:go run main.go server 9000 這樣的命令,就能夠開啓服務端監聽。服務器

假設server的ip爲192.168.1.3,那麼輸入:go run main.go client 192.168.1.3:9000便可鏈接到服務器並進入聊天室。併發

相關文章
相關標籤/搜索