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

李说的对 · · 823 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

问题描述

实现一个网络聊天室服务端。完成之后你将熟悉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)-网络聊天室

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

823 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传