美文网首页
golang练手小项目系列(4)-网络聊天室

golang练手小项目系列(4)-网络聊天室

作者: 李说的对 | 来源:发表于2019-06-28 19:21 被阅读0次

    问题描述

    实现一个网络聊天室服务端。完成之后你将熟悉select、net库、time定时器的用法。

    要点:

    用户发来的消息广播给所有接入聊天室的用户。

    新用户进入的时候能收到聊天室所有其他用户的名字列表。

    使用netcat工具作为客户端。

    拓展:

    当用户不活跃的时间超过指定时间后,断开用户的连接。

    代码:

    import (

      "bufio"

      "fmt"

      "log"

      "net"

      "time"

    )

    type client struct {

      Out  chan<- string

      Name string

    }

    var (

      entering = make(chan client)

      leaving = make(chan client)

      messages = make(chan string)

    )

    var timeout = 10 * time.Second

    func broadcaster()  {

      clients := make(map[client] bool)

      for {

          select {

          case msg := <-messages:

            for cli := range clients {

                cli.Out <- msg

            }

          case cli := <-entering:

            clients[cli] = true

            cli.Out <- "Present:"

            for c := range clients {

                cli.Out <- c.Name

            }

          case cli := <-leaving:

            delete(clients, cli)

            close(cli.Out)

          }

      }

    }

    func handleConn(conn net.Conn){

      out := make(chan string, 10)

      go clientWriter(conn, out)

      in := make(chan string)

      go clientReader(conn, in)

      var who string

      var nameTimer = time.NewTimer(timeout)

      out <- "Enter your name:"

      select {

      case name := <-in:

          who = name

      case <-nameTimer.C:

          conn.Close()

          return

      }

      cli := client{out, who}

      out <- "You are " + who

      messages <- who + " has arrived"

      entering <- cli

      idle := time.NewTimer(timeout)

    Loop:

      for {

          select {

          case msg := <-in:

            messages <- who + ": " + msg

            idle.Reset(timeout)

          case <-idle.C:

            conn.Close()

            break Loop

          }

      }

      leaving <- cli

      messages <- who + " has left"

      conn.Close()

    }

    func clientWriter(conn net.Conn, ch <-chan string)  {

      for msg := range ch{

          fmt.Fprintln(conn, msg)

      }

    }

    func clientReader(conn net.Conn, ch chan<- string) {

      input := bufio.NewScanner(conn)

      for input.Scan() {

          ch <- input.Text()

      }

    }

    func main() {

      listener, err := net.Listen("tcp", "localhost:8088")

      if err != nil{

          log.Fatal(err)

      }

      go broadcaster()

      for {

          conn, err := listener.Accept()

          if err != nil{

            log.Print(err)

            continue

          }

          go handleConn(conn)

      }

    }

    相关文章

      网友评论

          本文标题:golang练手小项目系列(4)-网络聊天室

          本文链接:https://www.haomeiwen.com/subject/wbaecctx.html