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

2019-06-28  本文已影响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)

  }

}

上一篇下一篇

猜你喜欢

热点阅读