使用Go实现一个百行聊天服务器

news2024/11/14 1:24:06

前段时间, redis作者不是整了个c语言版本的聊天服务器嘛, 地址, 代码量拢共不过百行.

于是, 心血来潮下, 我也整了个Go语言版本. 简单来说就是实现了一个聊天室的功能. 将所有注释空行都去掉, 刚好100行实现. 废话不多说, 先上代码:

package main

import (
	"fmt"
	"log"
	"net"
	"strings"
	"sync"
)

type Server struct { // 服务端内容
	clients map[string]*Client
	lock    sync.Mutex
}

func (s *Server) delClient(client *Client) { // 客户端关闭
	s.lock.Lock()
	defer s.lock.Unlock()
	delete(s.clients, client.name)
}

func (s *Server) addClient(client *Client) { // 客户端关闭
	s.lock.Lock()
	defer s.lock.Unlock()
	s.clients[client.name] = client
}

func (s *Server) sendMsgToOtherClient(msg string, client *Client) { // 将消息发送给其他所有客户端
	s.lock.Lock()
	defer s.lock.Unlock()
	// 将消息转发给其他客户端
	for _, c := range s.clients {
		if c != client {
			c.msgCh <- "msg-> " + client.name + ": " + msg + "\n"
		}
	}
}

type Client struct { // 定义客户端
	conn   net.Conn
	name   string      // 当前客户端的名称
	msgCh  chan string // 发送消息的管道
	server *Server
}

func (c *Client) receive() { // 接收消息
	for msg := range c.msgCh {
		_, _ = c.conn.Write([]byte(msg))
	}
}

func (c *Client) close() {
	c.server.delClient(c)
	close(c.msgCh)
	_ = c.conn.Close()
}

func (c *Client) handle() { // 开始处理连接
	_, _ = c.conn.Write([]byte(fmt.Sprintf("hello %s!\n", c.name))) // 发送欢迎信息
	c.server.sendMsgToOtherClient("join", c)                        // 通知大家, 有人加入了聊天室
	defer c.close()
	for {
		buf := make([]byte, 2048)
		n, err := c.conn.Read(buf) // 接收客户端发送的消息
		if err != nil {
			log.Printf("receive client data error: %s", err.Error())
			return
		}

		msg := strings.TrimSpace(string(buf[:n]))
		if len(msg) == 0 {
			continue
		}
		if msg == "quit" {
			c.server.sendMsgToOtherClient("quit", c) // 通知大家, 有人退出了聊天室
			return
		}
		c.server.sendMsgToOtherClient(msg, c)
	}
}

func main() {
	// 监听端口
	listener, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}
	server := &Server{
		clients: make(map[string]*Client),
		lock:    sync.Mutex{},
	}

	nameIndex := 1
	for {
		conn, err := listener.Accept() // 建立连接
		if err != nil {
			log.Println(err)
			continue
		}

		client := &Client{
			conn:   conn,
			msgCh:  make(chan string, 100),
			name:   fmt.Sprintf("user%d", nameIndex),
			server: server,
		}
		nameIndex++
		server.addClient(client)
		go client.handle()
		go client.receive()
		log.Printf("new client: %s\n", conn.RemoteAddr())
	}
}

可以直接telnet作为客户端连接, 实现的功能简单来说就是一个大的聊天室, 用户发的消息会同步发给所有用户. (因代码篇幅和复杂度原因, 就不对代码做详细说明了)

看下聊天室效果:

image-20231216220013277

当然了, 还是有很多极限情况没有处理, 很多异常情况没有判断. 比如:

  • 客户端数量没有控制
  • 缺少客户端心跳
  • 缺少错误处理
  • 缺少安全性检查
  • 客户端发送消息的长度限制
  • 等等…

但总得来说, 作为一个玩具还是可以的, 而且也达到百行的要求咯.(这也是我改了几版才改到百行的…)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1315986.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

区块链的可扩展性研究【06】Plasma

1.Plasma&#xff1a;Plasma 是一种基于以太坊区块链的 Layer2 扩容方案&#xff0c;它通过建立一个分层结构的区块链网络&#xff0c;将大量的交易放到子链上进行处理&#xff0c;从而提高了以太坊的吞吐量。Plasma 还可以通过智能合约实现跨链交易&#xff0c;使得不同的区块…

机器学习之无监督学习

聚类&#xff1a;发掘纵向结构的某种模式信息&#xff0c;某些x属于相同的分布或者类别 特征学习&#xff1a;发掘横向结构的某种模式信息&#xff0c;每一行都可以看成是一种属性或特征 密度估计&#xff1a;发掘底层数据分布&#xff0c;x都是从某个未知分布p(x)采出来的&a…

39、平均池化和全局平均池化

在了解了池化算法的基本概念之后,继续了解一个应用很广泛的池化,叫作全局平均池化。 先看下平均池化。平均池化就是在池化核标定的范围内,对像素取平均值然后作为输出。在很多AI框架或算法描述中,平均池化大概可以分为两种:一种叫作adaptive average pool(自适应平均池化…

Facebook广告系统结构

Facebook广告系统是一个复杂的大型系统&#xff0c;由多个组件和子系统相互配合工作&#xff0c;实现了广告的投放、拍卖、个性化推荐和效果评估等功能。下面小编讲讲Facebook广告系统的结构。 1、广告管理界面 广告管理界面是广告主与Facebook进行交互的入口&#xff0c;广告…

@PostMapping接收String类型的参数

接口这样定义&#xff1a; PostMapping("/aaa") public void getById(String param)参数这样测试&#xff1a;

腾讯云优惠全站搜——云服务器配置大全精准

腾讯云推出优惠全站搜页面 https://curl.qcloud.com/PPrF9NFe 在这个页面可以一键查询所需云服务器、轻量应用服务器、数据库、存储、CDN、网络、安全、大数据等云产品优惠活动大全&#xff0c;活动打开如下图&#xff1a; 腾讯云优惠全站搜——优惠合集 如上图&#xff0c;在这…

Linux下FFmepg使用

1.命令行录一段wav,PCM数据 ffmpeg -f alsa -i hw:0,0 xxx.wav//录制 ffplay out.wav//播放ffmpeg -f alsa -i hw:0,0 -ar 16000 -channels 1 -f s16le 1.pcm ffplay -ar 16000 -channels 1 -f s16le 1.pcm -ar freq 设置音频采样率 -ac channels 设置通道 缺省为1 2.将pcm…

10天玩转Python第7天:python 面向对象 全面详解与代码示例

今日内容 封装(定义类的过程) 案例(存放家具) 继承 多态 封装的补充 私有和公有权限属性的分类(实例属性, 类属性)方法的分类(实例方法, 类方法, 静态方法) 封装案例 # 定义家具类 class HouseItem: """家具类""" def __init__(self, name, a…

LT7911D是TYPE-C/DP或者EDP转2 PORT MIPI和LVDS加音频

1.概述&#xff1a; T7911D是一款高性能TYPE-C/DP/EDP转2 PORT MIPI或者LVDS的芯片&#xff0c;目前主要在AR/VR或者显示器上应用的很多&#xff0c;对于DP1.2输入&#xff0c;LT7911D可配置为1/2/4车道。自适应均衡化使其适用于长电缆应用&#xff0c;最大带宽可达21.6Gbps。…

Vue3报错: ‘defineProps‘ is not defined,解决方法

问题出现: 今天在使用 <script setup>组合式 API 的语法糖的时候&#xff0c;定义defineProps时候报错&#xff1a; ‘defineProps’ is not defined 查了一下资料&#xff0c;这是因为eslint的语法校验导致的问题。 解决方法1&#xff1a; 在项目根目录的文件.eslin…

时序预测 | Python实现XGBoost电力需求预测

时序预测 | Python实现XGBoost电力需求预测 目录 时序预测 | Python实现XGBoost电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从而可以将预期预测与当前最先进的行业预测进行比较…

JS中的String常用的实例方法

splice():分隔符 把字符串以分隔符的形式拆分为数组 const str pink,red;const arr str.split(,);console.log(arr);//Array[0,"pink";1:"red"]const str1 2022-4-8;const arr1 str1.split(-);console.log(arr1);//Array[0,"2022";1:"…

深入理解网络 I/O:单 Group 混杂模式|多 Group 主从模式

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

DS考研真题总结——客观题(1)

开始整理真题中的客观小题&#xff0c;至于和算法有关的大题统一最后整理~ 定义背诵&#xff1a;数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效…

现代雷达车载应用——第2章 汽车雷达系统原理 2.2节 汽车雷达架构

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.2 汽车雷达架构 从顶层来看&#xff0c;基本的汽车雷达由发射器&#xff0c;接收器和天线组成。图2.2给出了一种简化的单通道连续波雷达结构[2]。这…

javaEE -17(13000字 CSS3 入门级教程)

一&#xff1a;CSS3 简介 CSS3 是 CSS2 的升级版本&#xff0c;它在 CSS2 的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题&#xff0c;CSS3 在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …

Python基础01-环境搭建与输入输出

零、文章目录 Python基础01-环境搭建与输入输出 1、Python概述 &#xff08;1&#xff09;为什么要学习Python 技术趋势&#xff1a;Python自带明星属性&#xff0c;热度稳居编程语言界前三 简单易学&#xff1a;开发代码少&#xff0c;精确表达需求逻辑&#xff1b;33个关…

linux记录

一、修改eth0网口静态IP 1、sudo vim /etc/network/interfaces 2、按E进入编辑模式&#xff0c;按i进入编辑输入&#xff1a; auto eth0 iface eth0 inet static address 192.168.3.223 netmask 255.255.255.0 gateway 192.168.3.13、按Esc退出编辑&#xff1b;:wq保存文件并…

移植LVGL到像素屏,从此玩转像素屏0门槛

硬件方面 先上渲染图 实物图 配置 主控&#xff1a;esp32 micro32 plus主频&#xff1a;240MhzFlash&#xff1a;8MPSRAM&#xff1a;2M 软件方面 众所周知&#xff0c;LVGL是一个十分优秀的图形框架&#xff0c;小到几百kb的单片机&#xff0c;大到Linux都可以运行。既然它…

【Qt QML 入门】TextEdit

TextEdit可以显示多行可编辑的格式化文。默认是无边框的&#xff0c;可以和父控件完美融合。 import QtQuick import QtQuick.Window import QtQuick.ControlsWindow {id: winwidth: 800height: 600visible: trueTextEdit {id: textEditanchors.centerIn: parenttext: "He…