Golang服务端小项目

简单聊天室功能实现,没用框架,纯go语言,教程https://www.bilibili.com/video/BV1ZU4y1W72B
mac安装nc,使用nc命令模拟客户端,如 nc -v 172.0.0.1 8080

package main

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

type User struct {
	id   string
	name string
	msg  chan string
}

//搞一个key-value变量(map结构),并make出来空间
var allUsers = make(map[string]User)

//全局管道,进行广播
var message = make(chan string, 10)

func main() {
	listener, err := net.Listen("tcp", "172.0.0.1:8080")
	if err != nil {
		fmt.Println("服务器端提示:listen err:", err)
		return
	}

	//监听广播管道
	go broadcast()

	//持续监听新用户连接请求
	for {
		fmt.Println("服务器端提示:监听中...")
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("conn err:", err)
		}
		fmt.Println("服务器端提示:建立连接成功...")

		//握手成功
		go handler(conn)
	}

}

//连接完成,处理业务
func handler(conn net.Conn) {
	fmt.Println("服务器端提示:handle...")
	//把所有user写进map
	clientAddr := conn.RemoteAddr().String()
	newuser := User{
		id:   clientAddr,
		name: clientAddr,
		msg:  make(chan string),
	}
	allUsers[newuser.id] = newuser

	//写回客户端
	go writebackToClient(&newuser, conn)

	//退出账户
	var isQuit = make(chan bool)
	var timeReset = make(chan bool)
	go quit(isQuit, timeReset, &newuser, conn)

	//上线广播
	msginfo := fmt.Sprintf("id:%s,name:%s 上线了...\n", newuser.id, newuser.name)
	message <- msginfo

	//----------  处理具体业务	------------
	//持续接收客户端数据
	for {
		buf := make([]byte, 1024)
		//读取客户端数据到buf
		count, err := conn.Read(buf)
		//用户crtl+c退出
		if count == 0 {
			isQuit <- true
			return
		}
		if err != nil {
			fmt.Printf("服务器端提示:conn.Read err:%s,count:%d", err, count)
			return
		}

		//所有用户信息整理成一个字符串,并用回车换行
		var whoUser []string
		for _, user := range allUsers {
			userinfo := fmt.Sprintf("id:%s,name:%s", user.id, user.name)
			whoUser = append(whoUser, userinfo)
		}
		r := strings.Join(whoUser, "\n")

		//查询所有用户业务
		userInput := string(buf[:count-1])
		if len(userInput) == 5 && (userInput == "[who]" || userInput == "[WHO]") {
			newuser.msg <- (r + "\n")
			//修改名字
		} else if len(userInput) > 8 && (userInput[:8] == "[rename]") {
			newuser.name = strings.Split(userInput, "]")[1]
			allUsers[newuser.id] = newuser
			newuser.msg <- "[rename] successfully!\n"
		} else {
			message <- (userInput + "\n")
		}
		//重置计时器
		timeReset <- true
	}
	//----------  处理具体业务	------------

}

//广播消息
func broadcast() {
	fmt.Println("服务器端提示:广播启动成功...")
	defer fmt.Println("服务器端提示:广播异常退出...")

	for {
		info := <-message
		for _, user := range allUsers {
			user.msg <- info
		}
	}
}

//写回客户端
func writebackToClient(user *User, conn net.Conn) {
	fmt.Println("服务器端提示:writebackToClient启动...")
	for {
		data := <-user.msg //必须加上 <-
		conn.Write([]byte(data))
	}
	// for data := range user.msg {	//range下不用 <-
	// 	conn.Write([]byte(data))
	// }
}

//退出账户
func quit(isQuit, timeReset <-chan bool, user *User, conn net.Conn) {
	fmt.Println("服务器端提示:等待执行退出账户...")
	defer fmt.Println("服务器端提示:用户退出成功!")
	// if <-isQuit {
	// 	message <- fmt.Sprintf("username:%s退出\n", user.name)
	// 	delete(allUsers, user.id)
	// 	conn.Close()
	// 	return
	// }
	for {
		select {
		case <-isQuit:
			message <- fmt.Sprintf("username:%s主动退出", user.name)
			delete(allUsers, user.id)
			conn.Close()
			return
		case <-time.After(10 * time.Second):
			message <- fmt.Sprintf("username:%s超时退出", user.name)
			delete(allUsers, user.id)
			conn.Close()
			return
		case <-timeReset:
			fmt.Printf("客户端提示:uesrname:%s重置计时器成功\n", user.name)
		}
	}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值