吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3751|回复: 16
收起左侧

[其他转载] go语言聊天室

[复制链接]
logo_tu 发表于 2019-12-21 17:47
本帖最后由 logo_tu 于 2019-12-23 11:14 编辑

今天玩go语言,发现个聊天室挺好玩了,自己在稍微改装了一下。发给大家玩玩。
现在是12-23号上午,刚才测试了,亲测win7 win10能用

服务端
[Golang] 纯文本查看 复制代码
package main

import (
        "net"
        "fmt"
        "strings"
        "time"
        "io/ioutil"
)

// 创建用户结构体类型!
type Client struct {
        C    chan string
        Name string
        Addr string
}

// 创建全局map,存储在线用户
var onlineMap map[string]Client

// 创建全局 channel 传递用户消息。
var message = make(chan string)

func WriteMsgToClient(clnt Client, conn net.Conn) {
        // 监听 用户自带Channel 上是否有消息。
        for msg := range clnt.C {
                conn.Write([]byte(msg + "\n"))
        }
}

func MakeMsg(clnt Client, msg string) (buf string) {
        buf = clnt.Name + ": " + msg
        return
}

func HandlerConnect(conn net.Conn) {
        defer conn.Close()
        // 创建channel 判断,用户是否活跃。
        hasData := make(chan bool)

        // 获取用户 网络地址 IP+port
        netAddr := conn.RemoteAddr().String()
        // 创建新连接用户的 结构体. 默认用户是 IP+port
        clnt := Client{make(chan string), netAddr, netAddr}

        // 将新连接用户,添加到在线用户map中. key: IP+port value:client
        onlineMap[netAddr] = clnt

        // 创建专门用来给当前 用户发送消息的 go 程
        go WriteMsgToClient(clnt, conn)

        // 发送 用户上线消息到 全局channel 中
        //message <- "[" + netAddr + "]" + clnt.Name + "login"
        message <- MakeMsg(clnt, "上线!!!")

        // 创建一个 channel , 用来判断用退出状态
        isQuit := make(chan bool)

        // 创建一个匿名 go 程, 专门处理用户发送的消息。
        go func() {
                buf := make([]byte, 4096)
                for {
                        n, err := conn.Read(buf)
                        if n == 0 {
                                isQuit <- true
                                fmt.Printf("检测到客户端:%s退出\n", clnt.Name)
                                return
                        }
                        if err != nil {
                                fmt.Println("conn.Read err:", err)
                                return
                        }
                        // 将读到的用户消息,保存到msg中,string 类型
                        msg := string(buf[:n-2])
                        // 提取在线用户列表
                        if strings.Trim(msg, " ") == "who" {
                                conn.Write([]byte("online user list:\n"))
                                // 遍历当前 map ,获取在线用户
                                for _, user := range onlineMap {
                                        userInfo := user.Addr + ":" + user.Name + "\n"
                                        conn.Write([]byte(userInfo))
                                }
                                // 判断用户发送了 改名 命令
                        } else if len(msg) >= 8 && msg[:6] == "rename" { // rename|
                                newName := strings.Split(msg, "|")[1] // msg[8:]
                                clnt.Name = newName                   // 修改结构体成员name
                                onlineMap[netAddr] = clnt             // 更新 onlineMap
                                conn.Write([]byte("rename successful\n"))
                        } else {
                                // 将读到的用户消息,写入到message中。
                                message <- MakeMsg(clnt, msg)
                        }
                        hasData <- true
                }
        }()

        // 保证 不退出
        for {
                // 监听 channel 上的数据流动
                select {
                case <-isQuit:
                        delete(onlineMap, clnt.Addr)       // 将用户从 online移除
                        message <- MakeMsg(clnt, "logout") // 写入用户退出消息到全局channel
                        return
                case <-hasData:
                        // 什么都不做。 目的是重置 下面 case 的计时器。
                case <-time.After(time.Second * 60):
                        delete(onlineMap, clnt.Addr)                // 将用户从 online移除
                        message <- MakeMsg(clnt, "time out leaved") // 写入用户退出消息到全局channel
                        return
                }
        }
}
func check(e error) {
        if e != nil {
                panic(e)
        }
}
func Manager() {
        // 初始化 onlineMap
        onlineMap = make(map[string]Client)

        // 监听全局channel 中是否有数据, 有数据存储至 msg, 无数据阻塞。
        for {
                msg := <-message

                var d1 = []byte(msg)
                err2 := ioutil.WriteFile("./wechart.log", d1, 0666) //写入文件(字节数组)
                check(err2)

                // 循环发送消息给 所有在线用户。要想执行,必须 msg := <-message 执行完, 解除阻塞。
                for _, clnt := range onlineMap {
                        clnt.C <- msg
                }
        }
}

var URL = "0.0.0.0:8888"

func main() {

        // 创建监听套接字
        listener, err := net.Listen("tcp", URL)
        if err != nil {
                fmt.Println("Listen err", err)
                return
        }
        defer listener.Close()
        println("服务器创建成功...")
        // 创建管理者go程,管理map 和全局channel
        go Manager()

        // 循环监听客户端连接请求
        for {
                conn, err := listener.Accept()
                if err != nil {
                        fmt.Println("Accept err", err)
                        return
                }
                // 启动go程处理客户端数据请求
                go HandlerConnect(conn)
        }
}


用户端
[Golang] 纯文本查看 复制代码
package main

import (
        "fmt"
        "net"
        "os"
        "strings"
)

func main() {
        fmt.Println("正在连接服务器……")
        conn, err := net.Dial("tcp", "47.95.242.247:8888")
        if err != nil {
                fmt.Println("net.Dial error:", err)
                return
        }
        defer conn.Close()
        fmt.Println("连接服务器成功")

        //fmt.Println("先起一个名字吧:")
        //var userName string
        ////使用Scan输入,不允许出现空格
        //_, _ = fmt.Scan(&userName)
        //_, _ = conn.Write([]byte(userName))

        buf2 := make([]byte, 4096)
        _, err = conn.Read(buf2)
        if err != nil {
                fmt.Println("conn.Read error:", err)
                return
        }
        // 客户端收到“你好,***,欢迎来到够浪聊天室,请畅所欲言!”
        //        fmt.Println(string(buf2[:n]))
        fmt.Println("&#9888;提示:长时间没有发送消息会被系统强制踢出")
        // 获取用户 网络地址 IP+port
        netAddr := conn.LocalAddr().String()
        //客户端发送消息到服务器
        go func() {
                for {
                        buffer1 := make([]byte, 4096)
                        //这里使用Stdin标准输入,因为scanf无法识别空格
                        n, err := os.Stdin.Read(buffer1)
                        if err != nil {
                                fmt.Println("os.Stdin.Read error:", err)
                                continue
                        }
                        _, _ = conn.Write(buffer1[:n]) //写操作出现error的概率比较低,这里省去判断
                }
        }()
        //接收服务器发来的数据
        for {
                buffer2 := make([]byte, 4096)
                n, err := conn.Read(buffer2)
                if n == 0 {
                        fmt.Println("服务器已关闭当前连接,正在退出……")
                        return
                }
                if err != nil {
                        fmt.Println("conn.Read error:", err)
                        return
                }
                fmt.Print(strings.ReplaceAll(string(buffer2[:n]), netAddr, "我"))

        }

}


部服务端已经部署到服务器了,可以在线聊天哦。


客户端已经打包好了 地址 https://www.lanzouj.com/i87xfha






1576921550(1).jpg

centos7

centos7

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
夏橙M兮 + 1 + 1 谢谢@Thanks!
chomosuke + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

h2909198 发表于 2019-12-21 18:56
logo_tu 发表于 2019-12-21 17:51
ip暴露给大家了,不过应该没关系 ^_^

一会就有大佬顺着网线找你玩^_^
 楼主| logo_tu 发表于 2019-12-21 17:51
熊猫咖啡 发表于 2019-12-21 17:59
 楼主| logo_tu 发表于 2019-12-21 18:00
熊猫咖啡 发表于 2019-12-21 17:59
作为小白,看不懂,下载下来看看

来啊,坐等在线聊天
龙王的猫 发表于 2019-12-21 18:06
我进来了
 楼主| logo_tu 发表于 2019-12-21 18:08

我下班了!!!?
龙王的猫 发表于 2019-12-21 18:08
进不去=-=
 楼主| logo_tu 发表于 2019-12-21 18:20

win10可以,别的我就不知道啦(o^^o)
xouou 发表于 2019-12-21 18:31
win7 打开自动退出
头像被屏蔽
神秘高手Mars偉 发表于 2019-12-21 18:38
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 23:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表