zoukankan      html  css  js  c++  java
  • 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即可连接到服务器并进入聊天室。

  • 相关阅读:
    git 分支管理 (转自廖雪峰的git教程)
    git 命令
    java8 日期处理
    Softmax回归 softMax回归与logistic回归的关系
    决策树 学习提纲(需要解决的一些问题)
    spark UDAF
    似然函数
    spark RDD,DataFrame,DataSet 介绍
    scala LocalDateTime String 转换
    将java.util.Date类型转换成json时,使用JsonValueProcessor将date转换成希望的类型
  • 原文地址:https://www.cnblogs.com/K-artorias/p/8507848.html
Copyright © 2011-2022 走看看