Go实战--实现一个简单聊天室chatroom(The way to go)

来源:互联网 发布:网信办网络安全局 编辑:程序博客网 时间:2024/04/30 22:36

生命不止,继续 go go go !!!

上一篇博客跟大家介绍了,如何实现一个简单的tcp服务器和客户端,那么在此基础上,继续深耕一点点,介绍一下如何创建一个聊天室。

当然,还是还是一个要有一个服务端和若干个客户端。

server
net.Listen
Accept
这两个方法就不介绍了,之前都有提到过。

声明一个net.Conn数组,用于存放连接服务器的客户端:

var clients []net.Conn

大部分跟之前提到的tcp的server/client没有区别,最大的区别就是服务端收到消息后需要通知各个客户端,所以可以通过遍历数组cliQue来完成消息的通知。这里用到了for…range循环:

func notify(conn net.Conn, msg string) {    for _, con := range clients {        if con.RemoteAddr() != conn.RemoteAddr() {            con.Write([]byte(msg))        }    }}

顺便介绍一下RemoteAddr

func (c *IPConn) RemoteAddr() Addr

作用:
RemoteAddr returns the remote network address. The Addr returned is shared by all invocations of RemoteAddr, so do not modify it.

有一个客户端离开聊天室的时,要通知所有的客户端:

func disconnect(conn net.Conn, name string) {    for index, con := range clients {        if con.RemoteAddr() == conn.RemoteAddr() {            disMsg := name + " has left the room."            fmt.Println(disMsg)            clients = append(clients[:index], clients[index+1:]...)            notify(conn, disMsg)        }    }}

Go语言函数中有三个点…表示为可变参数,可以接受任意个数的参数。

append主要用于给某个切片(slice)追加元素

如果该切片存储空间(cap)足够,就直接追加,长度(len)变长;如果空间不足,就会重新开辟内存,并将之前的元素和新的元素一同拷贝进去

第一个参数为切片,后面是该切片存储元素类型的可变参数

client
客户端的代码就相对简单了很多。net.Dial也不再赘述。
注意就是从conn读数据,这里readStr[:length]用到了切片。

func read(conn net.Conn) {    for {        length, err := conn.Read(readStr)        if err != nil {            fmt.Printf("Error when read from server. Error:%s\n", err)            os.Exit(0)        }        fmt.Println(string(readStr[:length]))    }}

完整代码
服务端:

package mainimport (    "fmt"    "net"    "os")var clients []net.Connfunc main() {    var (        host   = "localhost"        port   = "8000"        remote = host + ":" + port        data   = make([]byte, 1024)    )    fmt.Println("Initiating server...")    lis, err := net.Listen("tcp", remote)    defer lis.Close()    if err != nil {        fmt.Printf("Error when listen: %s, Err: %s\n", remote, err)        os.Exit(-1)    }    for {        var res string        conn, err := lis.Accept()        if err != nil {            fmt.Println("Error accepting client: ", err.Error())            os.Exit(0)        }        clients = append(clients, conn)        go func(con net.Conn) {            fmt.Println("New connection: ", con.RemoteAddr())            // Get client's name            length, err := con.Read(data)            if err != nil {                fmt.Printf("Client %v quit.\n", con.RemoteAddr())                con.Close()                disconnect(con, con.RemoteAddr().String())                return            }            name := string(data[:length])            comeStr := name + " entered the room."            notify(con, comeStr)            // Begin recieve message from client            for {                length, err := con.Read(data)                if err != nil {                    fmt.Printf("Client %s quit.\n", name)                    con.Close()                    disconnect(con, name)                    return                }                res = string(data[:length])                sprdMsg := name + " said: " + res                fmt.Println(sprdMsg)                res = "You said:" + res                con.Write([]byte(res))                notify(con, sprdMsg)            }        }(conn)    }}func notify(conn net.Conn, msg string) {    for _, con := range clients {        if con.RemoteAddr() != conn.RemoteAddr() {            con.Write([]byte(msg))        }    }}func disconnect(conn net.Conn, name string) {    for index, con := range clients {        if con.RemoteAddr() == conn.RemoteAddr() {            disMsg := name + " has left the room."            fmt.Println(disMsg)            clients = append(clients[:index], clients[index+1:]...)            notify(conn, disMsg)        }    }}

客户端:

package mainimport (    "bufio"    "fmt"    "net"    "os")var writeStr, readStr = make([]byte, 1024), make([]byte, 1024)func main() {    var (        host   = "localhost"        port   = "8000"        remote = host + ":" + port        reader = bufio.NewReader(os.Stdin)    )    con, err := net.Dial("tcp", remote)    defer con.Close()    if err != nil {        fmt.Println("Server not found.")        os.Exit(-1)    }    fmt.Println("Connection OK.")    fmt.Printf("Enter your name: ")    fmt.Scanf("%s", &writeStr)    in, err := con.Write([]byte(writeStr))    if err != nil {        fmt.Printf("Error when send to server: %d\n", in)        os.Exit(0)    }    fmt.Println("Now begin to talk!")    go read(con)    for {        writeStr, _, _ = reader.ReadLine()        if string(writeStr) == "quit" {            fmt.Println("Communication terminated.")            os.Exit(1)        }        in, err := con.Write([]byte(writeStr))        if err != nil {            fmt.Printf("Error when send to server: %d\n", in)            os.Exit(0)        }    }}func read(conn net.Conn) {    for {        length, err := conn.Read(readStr)        if err != nil {            fmt.Printf("Error when read from server. Error:%s\n", err)            os.Exit(0)        }        fmt.Println(string(readStr[:length]))    }}

运行结果:
连接
这里写图片描述

聊天
这里写图片描述

离开
这里写图片描述

2 0
原创粉丝点击