当前位置: 首页 > news >正文

【Zinx】Day5-Part3:Zinx 的连接管理

目录

  • Day5-Part3:Zinx 的连接管理
    • 创建连接管理模块
    • 将连接管理模块集成到 Zinx 当中
      • 将 ConnManager 集成到 Server 当中
      • 在 Connection 的工厂函数中将连接添加到 ConnManager
      • Server 中连接数量的判断
      • 连接的删除
  • 补充:连接的带缓冲发包方式
  • 补充:注册连接启动/停止时自定义的 hook 方法

Day5-Part3:Zinx 的连接管理

现在我们要为 Zinx 框架增加连接个数的限定,如果与 Server 相连的 Client 超过了一定的个数,Zinx 为了保证后端的及时响应,应拒绝连接请求。

创建连接管理模块

我们分别在 zifaceznet 下建立 iconnmanager.goconnmanager.go

首先在 iconnmanager.go 当中定义接口:

package zifacetype IConnManager interface {Add(conn IConnection)                   // 添加连接Remove(conn IConnection)                // 删除连接Get(connID uint32) (IConnection, error) // 利用 ConnID 获取连接Len() int                               // 获取当前连接数量ClearConn()                             // 删除并停止所有连接
}

之后我们在 connmanager.go 当中定义连接管理模块 ConnManager,并使其实现 IConnManager 接口:

package znetimport ("errors""fmt""sync""zinx/ziface"
)type ConnManager struct {connections map[uint32]ziface.IConnection // 管理连接的信息connLock    sync.RWMutex                  // 读写连接的读写锁
}func NewConnManager() *ConnManager {return &ConnManager{connections: make(map[uint32]ziface.IConnection),}
}// Add 添加连接
func (connMgr *ConnManager) Add(conn ziface.IConnection) {// 保护共享资源 Map, 加写锁connMgr.connLock.Lock()defer connMgr.connLock.Unlock()// 将 conn 连接添加到 ConnManagerconnMgr.connections[conn.GetConnID()] = connfmt.Println("connection add to ConnManager successfully: conn num = ", connMgr.Len())
}// Remove 删除连接
func (connMgr *ConnManager) Remove(conn ziface.IConnection) {// 保护共享资源 map, 加写锁connMgr.connLock.Lock()defer connMgr.connLock.Unlock()// 删除连接信息delete(connMgr.connections, conn.GetConnID())fmt.Println("connection Remove connID = ", conn.GetConnID(), " successfully: conn num = ", connMgr.Len())
}// Get 利用 ConnID 获取连接
func (connMgr *ConnManager) Get(connID uint32) (ziface.IConnection, error) {// 保护共享资源 Map, 加读锁connMgr.connLock.RLock()defer connMgr.connLock.RUnlock()if conn, ok := connMgr.connections[connID]; ok {return conn, nil} else {return nil, errors.New("connection not found")}
}// Len 获取当前连接个数
func (connMgr *ConnManager) Len() int {return len(connMgr.connections)
}// ClearConn 停止并清除当前所有连接
func (connMgr *ConnManager) ClearConn() {// 保护共享资源 Map, 加写锁connMgr.connLock.Lock()defer connMgr.connLock.Unlock()// 停止并删除全部的连接信息for connID, conn := range connMgr.connections {// 停止conn.Stop()// 删除delete(connMgr.connections, connID)}fmt.Println("Clear All Connections successfully: conn num = ", connMgr.Len())
}

ConnManager 中,用一个 map 来承载全部的连接信息,key 是 ConnID,它在 Server 的 Start 方法中,调用 NewConnection 之前确定,而 value 就是对连接的封装 Connection 本身。ConnManager 中还定义了一个 connLock,它的作用是对 map 在多任务修改场景下进行并发保护。

Remove()方法用于删除指定的连接,而ClearConn()则会首先停止所有的连接,再删除,应当在服务器停止前调用。

将连接管理模块集成到 Zinx 当中

将 ConnManager 集成到 Server 当中

现在我们先将 ConnManager 集成到 Server 当中,作为 Server 的成员:

type Server struct {Name       string              // Name 为服务器的名称IPVersion  string              // IPVersion: IPv4 or otherIP         string              // IP: 服务器绑定的 IP 地址Port       int                 // Port: 服务器绑定的端口msgHandler ziface.IMsgHandle   // 将 Router 替换为 MsgHandler, 绑定 MsgId 与对应的处理方法ConnMgr    ziface.IConnManager // 当前 Server 的连接管理器
}
// NewServer 将创建一个服务器的 Handler
func NewServer() ziface.IServer {s := &Server{Name:       settings.Conf.Name,IPVersion:  "tcp4",IP:         settings.Conf.Host,Port:       settings.Conf.Port,msgHandler: NewMsgHandle(),ConnMgr:    NewConnManager(),}return s
}

既然 Server 具备了 ConnManager 成员,我们为其设置一个方法,用于获取 ConnManager 对象(通过成员函数来获取类内的成员):

// zinx/ziface/iserver.go
// 定义服务器接口
type IServer interface {Start()                                 // Start 启动服务器方法Stop()                                  // Stop 停止服务器方法Serve()                                 // Serve 开启服务器方法AddRouter(msgId uint32, router IRouter) // 路由功能: 给当前服务注册一个路由业务方法GetConnMgr() IConnManager               // 得到连接管理器
}
// zinx/znet/server.go
func (s *Server) GetConnMgr() ziface.IConnManager {return s.ConnMgr
}

我们可能会需要在 Connection 当中使用 ConnManager,毕竟 ConnManager 是对连接进行管理的模块,我们现在需要一种方法来使得 ConnManager 对 Connection 可见,Zinx 教程中采取的做法是将 Server 作为 Connection 成员的一部分,从而使得 Server 和 Connection 成为互相引用的关系,即:为 Connection 添加一个 Server 成员,使得 Connection 知晓自己隶属于哪个 Server 的管辖下:

type Connection struct {TCPServer    ziface.IServer    // 标记当前 Conn 属于哪个 ServerConn         *net.TCPConn      // 当前连接的 socket TCP 套接字ConnID       uint32            // 当前连接的 ID, 也可称为 SessionID, 全局唯一isClosed     bool              // 当前连接的开启/关闭状态Msghandler   ziface.IMsgHandle // 将 Router 替换为消息管理模块ExitBuffChan chan bool         // 告知该连接一经退出/停止的 channelmsgChan      chan []byte       // 无缓冲 channel, 用于读/写两个 goroutine 之间的消息通信msgBuffChan  chan []byte       // 定义 msgBuffChan
}

当然,传递进来的是 Server 的指针,不可能在服务器应用的运行时再复制一个 Server 的对象。可以这样理解,Connection 应该对其所属 Server 的指针具有访问权。

在 Connection 的工厂函数中将连接添加到 ConnManager

NewConnection 工厂函数调用时,由于 Connection 对象对其隶属的 Server 可见,直接调用 Server 的 GetConnMgr 方法并使用 ConnManager 的 Add 方法将 Connection 添加即可:

// NewConnection 创建新的连接
func NewConnection(server ziface.IServer, conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection {c := &Connection{TCPServer:    server,Conn:         conn,ConnID:       connID,isClosed:     false,Msghandler:   msgHandler,ExitBuffChan: make(chan bool, 1),msgChan:      make(chan []byte), // msgChan 初始化}// 将新创建的 Conn 添加到连接管理器中c.TCPServer.GetConnMgr().Add(c)return c
}

Server 中连接数量的判断

回顾我们引入连接管理模块的动机,我们建立连接管理模块,是为了控制连接的数量,以避免服务器同时与过多的客户端建立连接。因此,当连接建立之前,我们应该首先判断一下,当前与 Server 连接的 Client 的数量是否达到上限,如果达到了上限,那么就拒绝连接。实现的方法非常简单,在 Server 的 Start 方法下加入一个 if 条件句即可:

func (s *Server) Start() {fmt.Printf("[START] Server name: %s,listenner at IP: %s, Port %d is starting\n", s.Name, s.IP, s.Port)go func() {// ....// 3 启动server网络连接业务for {// 3.1 阻塞等待客户端建立连接请求conn, err := listenner.AcceptTCP()if err != nil {fmt.Println("Accept err ", err)continue}// 3.2 设置服务器最大连接控制,如果超过最大连接,那么则关闭此新的连接if s.ConnMgr.Len() >= settings.Conf.MaxConn {conn.Close()continue}//=============// 3.3 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的dealConn := NewConntion(s, conn, cid, s.msgHandler)cid ++// 3.4 启动当前链接的处理业务go dealConn.Start()}}()
}

当然,我们应该在 yaml 中定义好我们期望服务器连接的最大数目。

还有一点就是,服务器的连接控制或许可以引入 LRU 这类算法,比如长时间没有消息收发的 Client 可以做断连处理,从而接入新的连接。

连接的删除

在连接停止时,我们应该将连接从 ConnManager 当中删除,因此在 Connection 的 Stop 方法中使用 ConnManager 的 Remove:

// Stop 停止连接, 结束当前连接状态
func (c *Connection) Stop() {fmt.Println("Conn Stop()... ConnID = ", c.ConnID)// 1. 如果当前连接已经关闭if c.isClosed == true {return}c.isClosed = truefmt.Println("Im here")// 关闭 socket 连接c.Conn.Close()// 通知从缓冲队列读数据的业务, 该链接已经关闭c.ExitBuffChan <- true// 将连接从管理器中删除c.TCPServer.GetConnMgr().Remove(c)// 关闭该链接全部管道close(c.ExitBuffChan)close(c.msgBuffChan)
}

在 Server Stop 的时候,应该将连接全部清空,调用 ClearConn:

func (s *Server) Stop() {fmt.Println("[STOP] Zinx server , name ", s.Name)// Server.Stop() 将其它需要清理的连接信息或其他信息一并停止或清理s.ConnMgr.ClearConn()
}

至此我们成功地将连接管理模块集成到了 Zinx 当中。

补充:连接的带缓冲发包方式

这一部分与连接管理的关联不大,但是与 Zinx 的教学文档同时被列在第九节,因此作为补充写在连接管理的下方。

我们之前给 Connection 提供了一个 SendMsg() 方法,SendMsg() 当中,数据将会被发送到无缓冲的 msgChan 当中。如果客户端的连接较多,处理不及时,可能会产生短暂的阻塞,因此我们可以补充一个带有缓冲的消息发送方法,来做一些非阻塞的用户体验。

首先修改 Connection 的接口 IConnection,添加将消息发送到带缓冲区的通道的方法:

type IConnection interface {Start()                                      // 启动连接Stop()                                       // 停止连接GetConnID() uint32                           // 获取远程客户端地址信息GetTCPConnection() *net.TCPConn              // 从当前连接获取原始的 socket TCPConnRemoteAddr() net.Addr                        // 获取远程客户端地址信息SendMsg(msgId uint32, data []byte) error     // 直接将 Message 数据发给远程的 TCP 客户端SendBuffMsg(msgId uint32, data []byte) error // 添加带缓冲的发送消息接口
}

之后为 Connection 结构加入带缓冲区的 msgChan,并补充 SendBuffMsg(...) 方法:

type Connection struct {TCPServer    ziface.IServer    // 标记当前 Conn 属于哪个 ServerConn         *net.TCPConn      // 当前连接的 socket TCP 套接字ConnID       uint32            // 当前连接的 ID, 也可称为 SessionID, 全局唯一isClosed     bool              // 当前连接的开启/关闭状态Msghandler   ziface.IMsgHandle // 将 Router 替换为消息管理模块ExitBuffChan chan bool         // 告知该连接一经退出/停止的 channelmsgChan      chan []byte       // 无缓冲 channel, 用于读/写两个 goroutine 之间的消息通信msgBuffChan  chan []byte       // 定义 msgBuffChan
}// NewConnection 创建新的连接
func NewConnection(server ziface.IServer, conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection {c := &Connection{TCPServer:    server,Conn:         conn,ConnID:       connID,isClosed:     false,Msghandler:   msgHandler,ExitBuffChan: make(chan bool, 1),msgChan:      make(chan []byte), // msgChan 初始化msgBuffChan:  make(chan []byte, settings.Conf.MaxMsgChanLen),}// 将新创建的 Conn 添加到连接管理器中c.TCPServer.GetConnMgr().Add(c)return c
}func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error {if c.isClosed == true {return errors.New("Connection closed when send buff msg")}// 将 data 封包并发送dp := NewDataPack()msg, err := dp.Pack(NewMsgPackage(msgId, data))if err != nil {fmt.Println("Pack error msg id = ", msgId)return errors.New("Pack error msg")}c.msgBuffChan <- msgreturn nil
}

我们在 Writer 中也要对 msgBuffChan 进行数据监控,如果有数据发送到这个 channel,应当将数据写给客户端,因此在 select 中添加一个接收 msgBuffChan 数据的 case 事件:

func (c *Connection) StartWriter() {fmt.Println("[Writer Goroutine is running]")defer fmt.Println(c.RemoteAddr().String(), "[conn Writer exit!]")for {select {case data := <-c.msgChan:if _, err := c.Conn.Write(data); err != nil {fmt.Println("Send Data error:", err, " Conn Writer exit~")return}case data, ok := <-c.msgBuffChan:if ok {if _, err := c.Conn.Write(data); err != nil {fmt.Println("Send Buff Data error:", err, " Conn Writer exit")return}} else {// 注意: 这里刚才写错了, else 的对象是 ok 的 if 语句而不是 err 的 if 语句fmt.Println("msgBuffChan is Closed")return}case <-c.ExitBuffChan:// conn 关闭return}}
}

补充:注册连接启动/停止时自定义的 hook 方法

有时在创建连接之后,或是在连接断开之前,我们希望执行一些用户自定义的业务,所以我们为 Zinx 新增两个连接断开前和创建后的回调函数,它们也成为 hook(钩子)函数。

我们通过 Server 来注册 conn 的 hook 方法,首先修改 IServer 接口:

// 定义服务器接口
type IServer interface {Start()                                 // Start 启动服务器方法Stop()                                  // Stop 停止服务器方法Serve()                                 // Serve 开启服务器方法AddRouter(msgId uint32, router IRouter) // 路由功能: 给当前服务注册一个路由业务方法GetConnMgr() IConnManager               // 得到连接管理器SetOnConnStart(func(IConnection)) // 设置该 Server 在连接创建时的 hook 函数SetOnConnStop(func(IConnection))  // 设置该 Server 在连接断开时的 hook 函数CallOnConnStart(conn IConnection) // 调用连接 onConnStart Hook 函数CallOnConnStop(conn IConnection)  // 调用连接 onConnStop Hook 函数
}

再修改 Server:

type Server struct {Name       string              // Name 为服务器的名称IPVersion  string              // IPVersion: IPv4 or otherIP         string              // IP: 服务器绑定的 IP 地址Port       int                 // Port: 服务器绑定的端口msgHandler ziface.IMsgHandle   // 将 Router 替换为 MsgHandler, 绑定 MsgId 与对应的处理方法ConnMgr    ziface.IConnManager // 当前 Server 的连接管理器onConnStart func(conn ziface.IConnection) // Server 在连接创建时的 Hook 函数onConnStop  func(conn ziface.IConnection) // Server 在连接删除时的 Hook 函数
}

为 Server 实现 IServer 的方法:

func (s *Server) SetOnConnStart(hookFunc func(ziface.IConnection)) {s.onConnStart = hookFunc
}func (s *Server) SetOnConnStop(hookFunc func(ziface.IConnection)) {s.onConnStop = hookFunc
}func (s *Server) CallOnConnStart(conn ziface.IConnection) {if s.onConnStart != nil {fmt.Println("---> CallOnConnStart ...")s.onConnStart(conn)}
}func (s *Server) CallOnConnStop(conn ziface.IConnection) {if s.onConnStop != nil {fmt.Println("---> CallOnConnStop ...")s.onConnStop(conn)}
}

在连接创建的后调用 hook 方法:

// Start 实现 IConnection 中的方法, 它启动连接并让当前连接开始工作
func (c *Connection) Start() {// 开启处理该连接读取到客户端数据之后的业务请求go c.StartWriter()go c.StartReader()c.TCPServer.CallOnConnStart(c)for {select {case <-c.ExitBuffChan:// 得到退出消息则不再阻塞return}}
}

停止连接前调用 hook 方法:

// Stop 停止连接, 结束当前连接状态
func (c *Connection) Stop() {fmt.Println("Conn Stop()... ConnID = ", c.ConnID)// 1. 如果当前连接已经关闭if c.isClosed == true {return}c.isClosed = truefmt.Println("Im here")// Connection Stop() 如果用户注册了该连接的关闭回调业务, 那么应该在此刻显式调用c.TCPServer.CallOnConnStop(c)// 关闭 socket 连接c.Conn.Close()// 通知从缓冲队列读数据的业务, 该链接已经关闭c.ExitBuffChan <- true// 将连接从管理器中删除c.TCPServer.GetConnMgr().Remove(c)// 关闭该链接全部管道close(c.ExitBuffChan)close(c.msgBuffChan)
}

相关文章:

【Zinx】Day5-Part3:Zinx 的连接管理

目录 Day5-Part3&#xff1a;Zinx 的连接管理创建连接管理模块将连接管理模块集成到 Zinx 当中将 ConnManager 集成到 Server 当中在 Connection 的工厂函数中将连接添加到 ConnManagerServer 中连接数量的判断连接的删除 补充&#xff1a;连接的带缓冲发包方式补充&#xff1a…...

C语言:6.20字符型数据练习题

编写程序,输人一行数字字符(用回车结束),每个数字字符 的前后都有空格。 把这一行中的数字转换成一个整数。 例如,若输入(<CR>代表 Enter键):2 4 8 3<CR>则输出 整数:2483。 #include <stdio.h>int main() {char ch;int number 0;printf("请输入一行…...

SpringBoot Test详解

目录 spring-boot-starter-test 1、概述2、常用注解 2.1、配置类型的注解2.2、Mock类型的注解2.3、自动配置类型的注解2.4、启动测试类型的注解2.5、相似注解的区别和联系 3、SpringBootTest和Junit的使用 3.1、单元测试3.2、集成测试 4、MockMvc 4.1、简单示例4.2、自动配置4…...

CDefView::_GetPIDL函数分析之ListView_GetItem函数的参数item的item.mask 为LVIF_PARAM

CDefView::_GetPIDL函数分析之ListView_GetItem函数的参数item的item.mask 为LVIF_PARAM 第一部分&#xff1a; 1: kd> t SHELL32!CDefView::_GetPIDL: 001b:77308013 55 push ebp 1: kd> dv this 0x00000015 i 0n21 …...

Android Retrofit 框架注解定义与解析模块深度剖析(一)

一、引言 在现代 Android 和 Java 开发中&#xff0c;网络请求是不可或缺的一部分。Retrofit 作为 Square 公司开源的一款强大的类型安全的 HTTP 客户端&#xff0c;凭借其简洁易用的 API 和高效的性能&#xff0c;在开发者社区中广受欢迎。Retrofit 的核心特性之一便是通过注…...

项目上传到Gitee过程

在gitee上新建一个仓库 点击“克隆/下载”获取仓库地址 电脑上要装好git 在电脑本地文件夹右键“Git Bash Here” 依次执行如下命令 git init git remote add origin https://gitee.com/qlexcel/stm32-simple.git git pull origin master git add . git commit -m ‘init’…...

DeepSeek R1在医学领域的应用与技术分析(Discuss V1版)

DeepSeek R1作为一款高性能、低成本的国产开源大模型,正在深刻重塑医学软件工程的开发逻辑与应用场景。其技术特性,如混合专家架构(MoE)和参数高效微调(PEFT),与医疗行业的实际需求紧密结合,推动医疗AI从“技术驱动”向“场景驱动”转型。以下从具体业务领域需求出发,…...

数学之快速幂-数的幂次

题目描述 给定三个正整数 N,M,P&#xff0c;求 输入描述 第 1 行为一个整数 T&#xff0c;表示测试数据数量。 接下来的 T 行每行包含三个正整数 N,M,P。 输出描述 输出共 T 行&#xff0c;每行包含一个整数&#xff0c;表示答案。 输入输出样例 示例 1 输入 3 2 3 7 4…...

git subtree管理的仓库怎么删除子仓库

要删除通过 git subtree 管理的子仓库&#xff0c;可以按照以下步骤操作&#xff1a; 1. 确认子仓库路径 首先确认要删除的子仓库的路径&#xff0c;假设子仓库路径为 <subtree-path>。 2. 从主仓库中移除子仓库目录 使用 git rm 命令删除子仓库的目录&#xff1a; …...

学习资料电子版 免费下载的网盘网站(非常全!)

我分享一个私人收藏的电子书免费下载的网盘网站&#xff08;学习资料为主&#xff09;&#xff1a; link3.cc/sbook123 所有资料都保存在网盘了&#xff0c;直接转存即可&#xff0c;非常的便利&#xff01; 包括了少儿&#xff0c;小学&#xff0c;初中&#xff0c;中职&am…...

SpringMVC-全局异常处理

文章目录 1. 全局异常处理2. 项目异常处理方案2.1 异常分类2.2 异常解决方案2.3 异常解决方案具体实现 1. 全局异常处理 问题&#xff1a;当我们在SpingMVC代码中没有对异常进行处理时&#xff0c;三层架构的默认处理异常方案是将异常抛给上级调用者。也就是说Mapper层报错会将…...

基于Spring Boot的宠物健康顾问系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

【Linux内核系列】:深入理解缓冲区

&#x1f525; 本文专栏&#xff1a;Linux &#x1f338;作者主页&#xff1a;努力努力再努力wz ★★★ 本文前置知识&#xff1a; 文件系统以及相关系统调用接口 输入以及输出重定向 那么在此前的学习中&#xff0c;我们了解了文件的概念以及相关的系统调用接口&#xff0c;并…...

Python开发Scikit-learn面试题及参考答案

目录 如何用 SimpleImputer 处理数据集中的缺失值? 使用 StandardScaler 对数据进行标准化的原理是什么?与 MinMaxScaler 有何区别? 如何用 OneHotEncoder 对类别型特征进行编码? 解释特征选择中 SelectKBest 与 VarianceThreshold 的应用场景。 如何通过 PolynomialFe…...

~(取反)在算法竞赛中的常见用法和注意事项

在算法竞赛中&#xff0c;取反符号 ~ 主要用于按位取反操作&#xff0c;其功能是对整数的二进制表示逐位取反&#xff08;0 变 1&#xff0c;1 变 0&#xff09;。以下是 ~ 在算法竞赛中的常见用法和注意事项&#xff1a; 1. 按位取反的基本用法 ~ 对整数的二进制表示进行取反…...

C++ MySQL 常用接口(基于 MySQL Connector/C++)

C MySQL 常用接口&#xff08;基于 MySQL Connector/C&#xff09; 1. 数据库连接 接口&#xff1a; sql::mysql::MySQL_Driver *driver; sql::Connection *con;作用&#xff1a; 用于创建 MySQL 连接对象。 示例&#xff1a; driver sql::mysql::get_mysql_driver_insta…...

本地部署 OpenManus 保姆级教程(Windows 版)

一、环境搭建 我的电脑是Windows 10版本&#xff0c;其他的没尝试&#xff0c;如果大家系统和我的不一致&#xff0c;请自行判断&#xff0c;基本上没什么大的出入啊。 openManus的Git地址&#xff1a;https://github.com/mannaandpoem/OpenManus 根据官网的两种安装推荐方式如…...

【Pandas】pandas Series compare

# Pandas2.2 Series ## Computations descriptive stats |方法|描述| |-|:-------| |Series.compare(other[, align_axis, ...])|用于比较两个 Series| ### pandas.Series.compare pandas.Series.compare 方法用于比较两个 Series&#xff0c;并返回一个包含差异的 DataFram…...

基于DeepSeek的智慧医药系统(源码+部署教程)

运行环境 智慧医药系统运行环境如下&#xff1a; 前端&#xff1a; HTMLCSS后端&#xff1a;Java AIGCDeepseekIDE工具&#xff1a;IDEA技术栈&#xff1a;Springboot HTMLCSS MySQL 主要角色 智慧医药系统主要分为两个角色。 游客 尚未进行注册和登录。具备登录注册、…...

如何为服务设置合理的线程数

1. 首先&#xff0c;要确定最大线程数的限制因素。通常&#xff0c;线程数量受限于内存、CPU和操作系统限制。比如&#xff0c;每个线程都需要一定的栈内存&#xff0c;默认情况下Java线程的栈大小是1MB&#xff08;64位系统可能更大&#xff09;&#xff0c;所以如果内存不足&…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...