golang聊天室

golang对并发的支持非常好,就是因为他有一个goroutine机制和channel机制,实现并发场景轻松高效。

下面我们实现一个聊天室程序,代码不多,但是功能很强大

//代码转载自: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即可连接到服务器并进入聊天室。

posted @ 2018-03-05 10:58  K_artorias  阅读(338)  评论(0编辑  收藏  举报