zoukankan      html  css  js  c++  java
  • [GO]并发实现聊天室服务器

    package main

    import (
    "net"
    "fmt"
    "strings"
    "time"
    )

    type Client struct {
    C chan string //用户发送数据的通道
    Name string //用户名
    Addr string //网络地址
    }

    //保存在线用户 cliaddr ======> client
    var onlineMap map[string]Client

    var message = make(chan string)

    func WriteMsgToClient(cli Client, conn net.Conn) {
    for msg := range cli.C {
    //给当前客户端发送信息
    conn.Write([]byte(msg + " "))
    }
    }

    func MakeMsg(cli Client, msg string) (buf string) {
    buf = "[" + cli.Addr + "]" + cli.Name + ": login"
    return
    }

    func HandleConn(conn net.Conn) { //处理用户连接
    defer conn.Close()
    //获取客户端的网络地址
    cliAddr := conn.RemoteAddr().String()
    //创建一个结构体
    cli := Client{make(chan string), cliAddr, cliAddr}
    //把结构体添加到map
    onlineMap[cliAddr] = cli

    //新开一个协程,专门给当前客户端发送信息
    go WriteMsgToClient(cli, conn)

    //广播某个人在线
    message <- MakeMsg(cli, "login")

    //提示,我是谁
    cli.C <- MakeMsg(cli, "I am here")

    var isQuit = make(chan bool)

    hasData := make(chan bool)

    go func() {
    buf := make([]byte, 2048)
    for true {
    n, err := conn.Read(buf)
    if n == 0 { //对方断开,或者出问题
    isQuit <- true
    fmt.Println("conn.read err = ", err)
    return
    }
    msg := string(buf[:n-1])
    if len(msg) == 3 && msg == "who" {
    conn.Write([]byte("user list : "))
    for _, tmp := range onlineMap {
    msg = tmp.Addr + ":" + tmp.Name + " "
    conn.Write([]byte(msg))
    }
    }else if len(msg) >= 8 && msg[:6] == "rename" {
    //rename|mike
    name := strings.Split(msg,"|")[1]
    cli.Name = name
    onlineMap[cliAddr] = cli
    conn.Write([]byte("user list : "))
    }else {
    message <- MakeMsg(cli, msg)
    }
    }
    }()

    for true {
    select {
    case <- isQuit:
    delete(onlineMap, cliAddr) //当前用户从map移除
    message <- MakeMsg(cli, "log out") //广播谁下线了
    return
    case <- hasData:
    //不做操作
    case time.After(60*time.Second): //60秒都没有操作了,超时
    delete(onlineMap, cliAddr) //当前用户从map移除
    message <- MakeMsg(cli, "tiem out") //广播谁下线了
    return
    }
    }
    }

    func Manager() {
    //给map分配空间map
    onlineMap = make(map[string]Client)

    for true {
    msg := <-message //没有消息前,这里会阻塞
    //遍历map,给map每个成员都发送此消息
    for _, cli := range onlineMap{
    cli.C <- msg
    }
    }

    }

    func main() {
    //创建监听
    listener, err := net.Listen("tcp", ":8000")
    if err != nil {
    fmt.Println("net.Listen err = ", err)
    return
    }

    //新开一个协程,用于转发消息,只要有消息到达 ,那就遍历map然后给map每个成员都发送消息
    go Manager()

    //主协程,循环阻塞等待用户连接
    for true {
    conn, err := listener.Accept()
    if err != nil {
    fmt.Println("listener.Accept err = ", err)
    continue //如果这个不发,説不定还有下个发呢
    }
    //处理用户的连接
    go HandleConn(conn)
    }
    }

    执行的结果,当有任何一个新用户登录了,其他所有的用户都会收到登录提醒,这里以ip加端口号的试做为一个唯一标识 

  • 相关阅读:
    php基础的一点注意事项
    每天学习一点点--word-break和word-wrap用法和区别
    line-height的一点粗浅认识
    图片的无缝滚动效果
    CSS篇章
    redis 3.0 集群__数据迁移和伸缩容
    redis 3.0 集群__使用
    官方教程文档地址
    redis 3.0 集群__安装
    java 泛型的使用
  • 原文地址:https://www.cnblogs.com/baylorqu/p/9687326.html
Copyright © 2011-2022 走看看