码迷,mamicode.com
首页 > 其他好文 > 详细

goland 简单聊天室服务端

时间:2019-01-03 22:42:11      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:lis   rename   map   type   数据   pack   ring   连接   信息   

package main

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

type Client struct {
	C       chan string //用于发送数据的管道
	Name    string      //用户名
	Address string      //IP地址
}

//保存在线用户
var onLineMap map[string]Client

var message = make(chan string)

func Manager() {
	onLineMap = make(map[string]Client)
	for {
		msg := <-message //阻塞等待消息
		for _, cli := range onLineMap {
			cli.C <- msg
		}
	}
}

//发送消息给客户端
func WriteMessageToClient(cli Client, conn net.Conn) {
	for msg := range cli.C {
		//发送消息
		conn.Write([]byte(msg + "\n"))
	}
}
func MakeMsg(cli Client, msg string) (buf string) {
	buf = "[" + cli.Address + "]" + cli.Name + ":" + msg
	return
}

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

	//新建协程,发送消息给客户端
	go WriteMessageToClient(cli, conn)
	//广播某人在线
	message <- MakeMsg(cli, "login")
	cli.C <- MakeMsg(cli, "i am here")

	isQuit := make(chan bool)  //用户是否主动退出
	hasData := make(chan bool) //用户是否发送过数据
	//新建协程接收用户发送信息
	go func() {
		buf := make([]byte, 2048)
		for {
			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:\n"))
				for _, data := range onLineMap {
					msg = data.Address + ":" + data.Name + "\n"
					conn.Write([]byte(msg))
				}
			} else if len(msg) >= 8 && msg[:6] == "rename" {
				//修改用户名
				cli.Name = strings.Split(msg, "|")[1]
				onLineMap[cli.Address] = cli
				conn.Write([]byte("rename success\n"))
			} else {
				//转发消息
				message <- MakeMsg(cli, msg)
			}
			hasData <- true
		}
	}()

	for {
		select {
		case <-isQuit:
			delete(onLineMap, cli.Address) //用户退出登录,移除用户
			message <- MakeMsg(cli, "login out")
			return
		case <-hasData:
		case <-time.After(60 * time.Second): //用户60秒不操作自动超时
			delete(onLineMap, cli.Address) //用户退出登录,移除用户
			message <- MakeMsg(cli, "time out leave out")
			return
		}
	}
}
func main() {
	//监听
	listener, err := net.Listen("tcp", ":8000")
	if err != nil {
		fmt.Println("net.Listen err=", err)
		return
	}
	defer listener.Close()

	//新建一个协程,转发消息
	go Manager()

	//主协程
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener.Accept err=", err)
			continue
		}
		go HandleConn(conn) //处理用户连接
	}
}

  

goland 简单聊天室服务端

标签:lis   rename   map   type   数据   pack   ring   连接   信息   

原文地址:https://www.cnblogs.com/lemonzwt/p/10217190.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!