Go语言实现长连接并发框架 - 请求分发器

文章目录

前言

你好,我是醉墨居士,我们上篇博客实现了任务管理器的功能,接下来这篇博客我们将要实现请求分发模块的开发

接口

trait/dispatcher.go

go 复制代码
type Dispatcher interface {
	Start()
	Dispatch(connQueue chan Connection)
	BatchDispatch(conn Connection) error
	SetHeaderDeadline(deadline time.Time)
	SetBodyDeadline(deadline time.Time)
	ChooseQueue(conn Connection) chan <- Connection
	Commit(conn Connection)
}

结构体

gcore/dispatcher.go

go 复制代码
// Dispatcher 请求分发模块,负责读取客户端连接的数据,并对数据进行拆包转换成消息格式,然后分发给下游的任务处理模块对消息进行业务处理
type Dispatcher struct {
	headerDeadline time.Time
	bodyDeadline time.Time

	connQueue []chan trait.Connection
	taskMgr trait.TaskMgr
}

// NewDispatcher 创建一个请求分发器
func NewDispatcher(taskMgr trait.TaskMgr) *Dispatcher {
	connQueue := make([]chan trait.Connection, global.Config.DispatcherQueues)
	for i := 0; i < len(connQueue); i++ {
		connQueue[i] = make(chan trait.Connection, global.Config.DispatcherQueueLen)
	}

	return &Dispatcher{
		connQueue: connQueue,
		taskMgr: taskMgr,
	}
}

接口实现

gcore/dispatcher.go

go 复制代码
// Start 启动请求分发模块
func (d *Dispatcher) Start() {
	for i := 0; i < len(d.connQueue); i++ {
		for j := 0; j < global.Config.DispatcherQueueLen; j++ {
			go d.Dispatch(d.connQueue[i])
		}
	}
}

// StartDispatcher 分发连接数据
func (d *Dispatcher) Dispatch(connQueue chan trait.Connection) {
	// 从conn中读取数据,并将数据提交给taskMgr处理
	for conn := range connQueue {
		d.BatchDispatch(conn)
	}
}

// BatchDispatch 批量读取连接中的数据,并封装成请求,然后分发请求
func (d *Dispatcher) BatchDispatch(conn trait.Connection) error {
	for time.Now().After(d.headerDeadline) {
		header := make([]byte, 4)

		// 设置header读取超时时间
		conn.SetReadDeadline(d.headerDeadline)

		_, err := io.ReadFull(conn, header)
		if err != nil {
			if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
				// 数据包读取超时
				return nil
			}

			return err
		}

		// 设置body读取超时时间
		conn.SetReadDeadline(d.bodyDeadline)

		// 读取长度
		dataLen := binary.BigEndian.Uint16(header[2:4])
		// 读取数据
		body := make([]byte, dataLen)	
		_, err = io.ReadFull(conn, body)
		if err != nil {
			return err
		}

		msg := gpack.Unpack(header, body)
		// 提交消息,处理数据
		
		request := NewRequest(conn, msg)

		d.taskMgr.Submit(request)
	}

	return nil
}

// SetHeaderDeadline 设置header读取超时时间
func (d *Dispatcher) SetHeaderDeadline(deadline time.Time) {
	d.headerDeadline = deadline
}

// SetBodyDeadline 设置body读取超时时间
func (d *Dispatcher) SetBodyDeadline(deadline time.Time) {
	d.bodyDeadline = deadline
}

// ChooseQueue 选择处理连接的队列
func (d *Dispatcher) ChooseQueue(conn trait.Connection) chan <- trait.Connection {
	// 负载均衡,选择队列
	return d.connQueue[conn.ID() % int32(len(d.connQueue))]
}

// Commit 提交连接到队列
func (d *Dispatcher) Commit(conn trait.Connection) {
	d.ChooseQueue(conn) <- conn
}

项目地址

Github:https://github.com/zm50/gte

Giee:https://gitee.com/zm50/gte

最后

我是醉墨居士,我们完成了基本的请求分发器的开发,希望对你有所帮助,也希望你有所收获

相关推荐
island13148 分钟前
CANN GE(图引擎)深度解析:计算图优化管线、内存静态规划与异构 Stream 调度机制
c语言·开发语言·神经网络
呉師傅9 分钟前
【使用技巧】Adobe Photoshop 2024调整缩放与布局125%后出现点菜单项漂移问题的简单处理
运维·服务器·windows·adobe·电脑·photoshop
云姜.10 分钟前
线程和进程的关系
java·linux·jvm
曹牧12 分钟前
Spring Boot:如何在Java Controller中处理POST请求?
java·开发语言
浅念-15 分钟前
C++入门(2)
开发语言·c++·经验分享·笔记·学习
WeiXiao_Hyy16 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
玄同76517 分钟前
SQLite + LLM:大模型应用落地的轻量级数据存储方案
jvm·数据库·人工智能·python·语言模型·sqlite·知识图谱
吾日三省吾码18 分钟前
别只会“加索引”了!这 3 个 PostgreSQL 反常识优化,能把性能和成本一起打下来
数据库·postgresql
chian-ocean20 分钟前
百万级图文检索实战:`ops-transformer` + 向量数据库构建语义搜索引擎
数据库·搜索引擎·transformer
User_芊芊君子22 分钟前
CANN010:PyASC Python编程接口—简化AI算子开发的Python框架
开发语言·人工智能·python