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

施磊老师基于muduo网络库的集群聊天服务器(四)

文章目录

  • 实现登录业务
    • 登录业务代码
    • 补全数据库接口:查询,更新状态
    • 注意学习一下里面用到的数据库api
    • 测试与问题
      • **问题1:**
      • **问题2:**
  • 用户连接信息与线程安全
    • 聊天服务器是长连接服务器
    • 如何找到用户B的连接?
    • 在业务层存储用户的连接信息
    • 多线程安全问题
    • 加锁!
  • 处理客户端异常退出
    • 处理情况:-功能不完善
    • 两个任务:
    • 测试
  • 点对点聊天业务(在线)
    • 传什么?
    • 业务处理逻辑
    • 代码结构规划
    • 调试与测试:
  • 离线消息存储业务
    • 设计数据库表:
    • Model 类封装:
    • 操作流程:
    • 代码结构:-单台
    • 问题
    • 测试
  • 服务器异常下线
    • 功能不完整
    • 解决核心
    • 解决步骤
    • 低耦合性
    • 代码结构
    • 测试

实现登录业务

登录业务代码

要考虑细一点: 登陆成功, 登录失败, 哪里失败了, 登录成功更新状态

chatservice.cpp

// 处理登录业务
void ChatService::login(const TcpConnectionPtr &conn, json &js, Timestamp time)
{// LOG_INFO<<"do login service"; //测试用//int id = js["id"];int id = js["id"].get<int>();  // js字符串 转成整型string pwd = js["password"];User user = _usermodel.query(id);if (user.getId() == id && user.getPwd() == pwd) // id默认为-1{// 登陆成功if (user.getState() == "online") // 用户在线, 不允许重复登录{json response;response["msgid"] = LOGIN_MSG_ACK;response["errno"] = 2;response["errmsg"] = "用户已经登录, 不允许重复登录!";conn->send(response.dump());}else{user.setState("online");   //登录成功, 更新状态_usermodel.updateState(user);  // 刷新状态json response;response["msgid"] = LOGIN_MSG_ACK;response["errno"] = 0;response["id"] = user.getId();response["name"] = user.getName();conn->send(response.dump());}}else{// 登录失败if (user.getId() == -1) // 没找到{json response;response["msgid"] = LOGIN_MSG_ACK;response["errno"] = 1;response["errmsg"] = "用户名不存在!";conn->send(response.dump());}else if (user.getPwd() != pwd){json response;response["msgid"] = LOGIN_MSG_ACK;response["errno"] = 3;response["errmsg"] = "密码错误!";conn->send(response.dump());}}
}

补全数据库接口:查询,更新状态

usermodel.hpp

// 更新 用户状态信息bool updateState(User user);

usermodel.cpp

User UserModel::query(int id)
{//1. 组装 sql语句char sql[1024]={0};sprintf(sql, "select * from user where id=%d", id);MySQL mysql;if(mysql.connect()){MYSQL_RES *res = mysql.query(sql);   // 数据库apiif(res!=nullptr){MYSQL_ROW row = mysql_fetch_row(res);if(row != nullptr){User user;user.setId(atoi(row[0]));user.setName(row[1]);user.setPwd(row[2]);user.setState(row[3]);mysql_free_result(res); // 释放一下资源, 否则内存不断泄露return user;}}}return false;}// 更新 用户状态信息
bool UserModel::updateState(User user)
{//1. 组装 sql语句char sql[1024]={0};sprintf(sql, "update user set state='%s' where id=%d",user.getState().c_str(), user.getId());MySQL mysql;if(mysql.connect()){if(mysql.update(sql)){return true;}}return false;
}

注意学习一下里面用到的数据库api

测试与问题

问题1:

reason: [json.exception.type_error.302] type must be number, but is null

检查一下, 本代码 使用 用户id 进行登录, 而不是用户名!

测试的话, 事先查一下 用户id

{"msgid":1,"id":22,"password":"101010"}

问题2:

.get<int>()–js字符串转整型–>错误, 不支持 字符串转int

  • get<T>() 不是设计用来做隐式转换的,而是严格类型检查工具
  • 它的意义在于 强制开发者明确处理类型问题,避免隐藏的运行时错误。
int id = js["id"].get<int>();  // js字符串 转成整型
{"msgid":1,"id":22,"password":"101010"}
//还没有设计下线 状态改变,  自己多试试那几种登录情况

js["id"]int 的几种方式

  1. js["id"].get<int>()
    • "id":2222
    • "id":"22"抛出异常(需 try-catch
  2. int id = js["id"]
    • "id":2222(隐式转换)
    • "id":"22"编译错误
  3. js.value("id", 0)
    • "id":2222
    • "id":"22"返回默认值 0(不抛异常)

用户连接信息与线程安全

聊天服务器是长连接服务器

长连接的特点

  1. 持久连接:客户端与服务器建立连接后保持长时间开放
  2. 双向通信:服务器可以主动向客户端推送消息
  3. 低延迟:省去了频繁建立/断开连接的开销

聊天服务器为何适合长连接

  1. 实时性要求:需要即时推送新消息给在线用户
  2. 频繁交互:聊天场景下用户会持续发送和接收消息
  3. 状态保持:可以维持用户在线状态、未读消息等上下文

如何找到用户B的连接?

服务器必须主动推:当用户A发给用户B时,服务器需要立刻找到用户B的连接,把消息推过去

**解决方案:**维护一个"用户ID ⇨ 连接"的映射表

在业务层存储用户的连接信息

include/server/chatservice.hpp

//存储在线用户的 连接信息unordered_map<int, TcpConnectionPtr> _userConnMap; // 只有登录成功了, 才会存储

src/server/chatservice.cpp

//登陆成功里 添加---具体看自己代码, 哪里是登陆成功
// 存储用户登录信息// _userConnMap.insert({id, conn});_userConnMap.emplace(id,conn);

多线程安全问题

onMessage()—> 在网络库中, 会被多线程调用, 业务层要 考虑 现成安全

在线用户信息 在 运行中, 是不断改变的, 一定要考虑 线程安全!!

加锁!

锁的力度 一定要小!!!

include/server/chatservice.hpp

//定义互斥锁, 保证_userConnMap安全mutex _connMutex;//存储在线用户的 连接信息unordered_map<int, TcpConnectionPtr> _userConnMap; // 只有登录成功了, 才会存储

src/server/chatservice.cpp

使用 作用域, 时加锁力度 尽可能小!!

// 存储用户登录信息// _userConnMap.insert({id, conn});{lock_guard<mutex> lock(_connMutex); // 自动解锁_userConnMap.emplace(id,conn);}

处理客户端异常退出

处理情况:-功能不完善

必须是客户端 断开连接, 服务端不能断开, 就算是 服务端断开连接, 客户端必须先退出, 否则 这个 修改状态 无法完成

客户端只要断开连接, 就需要修改用户的 状态

两个任务:

  1. 删除该用户的 在线用户连接信息
  2. 修改用户在数据库中的状态

include/server/chatservice.hpp

// 客户端异常退出处理void clientCloseException(const TcpConnectionPtr &conn);

src/server/chatservice.cpp

// 客户端异常退出处理void ChatService::clientCloseException(const TcpConnectionPtr &conn)
{User user;{lock_guard<mutex> lock(_connMutex);for (auto it = _userConnMap.begin(); it != _userConnMap.end(); ++it){if (it->second == conn){user.setId(it->first);_userConnMap.erase(it);break;}}}if(user.getId()!=-1){//更新用户状态信息user.setState("offline");_usermodel.updateState(user);}}

src/server/chatserver.cpp

void ChatServer::onConnect(const TcpConnectionPtr& conn)
{// 客户端断开连接 if(!conn->connected()){//客户端异常退出ChatService::instance()->clientCloseException(conn);conn->shutdown();}
}

测试

一定要退出 telnet

完成

点对点聊天业务(在线)

传什么?

msgid: //说明是什么业务
fromid: id
fromname:
to: id
msg: "......"

业务处理逻辑

客户端发送聊天消息 → 服务器收到并解析

首先判断接收者(to)是否在线:

  • **在线:**直接通过 connection 转发消息
  • **离线:**将消息存入离线消息表(后续上线时再发送)

为保证线程安全,访问用户连接表时加锁(用 lock_guard

代码结构规划

include/public.hpp

ONE_CHAT_MSG //一对一聊天

include/server/chatservice.hpp

// 一对一 聊天业务void oneChat(const TcpConnectionPtr &conn, json &js, Timestamp time);

src/server/chatservice.cpp

// 一对一 聊天业务  并进行处理器绑定
void ChatService::oneChat(const TcpConnectionPtr &conn, json &js, Timestamp time)
{int toid = js["to"].get<int>();{lock_guard<mutex> lock(_connMutex);auto it = _userConnMap.find(toid);if(it!=_userConnMap.end()){//在线, 转发消息it->second->send(js.dump());return;}}//不在线, 存储离线消息}

调试与测试:

  • 使用手动构造 JSON 数据模拟客户端行为进行测试
  • 验证用户注册、登录、消息发送与接收是否正常
{"msgid":1,"id":22,"password":"101010"}
{"msgid":3,"name":"hzh1","password":"101010"}
{"msgid":1,"id":23,"password":"101010"}
{"msgid":5,"id":22,"from":"hzh","to":23,"msg":"i am hzh!hello!"}
{"msgid":5,"id":23,"from":"hzh1","to":22,"msg":"我不认识你!"}

离线消息存储业务

设计数据库表:

  • 创建 offline_message 表,包含 user_idmessage 两个字段。
  • 这样设计是为了简单高效地存储每个用户的离线消息。

Model 类封装:

定义了 OfflineMessage 类来封装与离线消息表的交互。这样做的目的是将数据库操作与业务逻辑解耦,符合“分层设计”的原则。通过这一层的封装,业务代码与数据库操作分离,减少了耦合,提高了代码的可维护性。

  • 创建 OfflineMessage 类,提供方法:
    • insert: 存储离线消息。
    • remove: 删除某个用户的所有离线消息(避免用户登录后再收到历史消息)。
    • query: 查询用户的所有离线消息,返回一个 vector 容器。

操作流程:

  • 插入消息:当用户不在线时,将消息存入 offline_message 表。
    • 离线消息的增加会在数据库表 offlinemessage 中插入一条新记录。即使 userid相同,每次插入的消息都会作为一条独立的记录存储在表中,因为没有任何逻辑限制userid的重复。
  • 查询消息:用户登录时,查询该用户的所有离线消息,并返回给用户。
    • 由于会重复, 所以 要用vector, 每条都加进去
  • 删除消息:用户登录后,查询并返回离线消息后,删除该用户的所有消息,确保下次登录时不再重复。

代码结构:-单台

还不考虑 在另一台 上, 需要同步消息

include/server/offlinemessagemodel.hpp

#ifndef OFFLINEMESSAGEMODEL_H
#define OFFLINEMESSAGEMODEL_H#include <string>
#include <vector>
using namespace std;// 提供离线消息表的操作接口方法
class OfflineMessageModel
{
public:// 添加离线消息void insert(int userid, const string &msg);// 删除离线消息void remove(int userid);// 查询离线消息vector<string> query(int userid);
};#endif

src/server/offlinemessagemodel.cpp

#include "offlinemessagemodel.hpp"
#include "db.h"
#include <iostream>// 添加离线消息
void OfflineMessageModel::insert(int userid, const string &msg)
{// 1. 创建数据库连接// 2. 执行 SQL 语句插入离线消息// 3. 关闭数据库连接// 4. 返回插入结果char sql[1024] = {0};sprintf(sql, "insert into offlinemessage (userid, message) values (%d, '%s')", userid, msg.c_str());MySQL mysql;if (mysql.connect()){mysql.update(sql);}}// 删除离线消息
void OfflineMessageModel::remove(int userid)
{// 1. 创建数据库连接// 2. 执行 SQL 语句删除离线消息// 3. 关闭数据库连接// 4. 返回删除结果char sql[1024] = {0};sprintf(sql, "delete from offlinemessage where userid = %d", userid);MySQL mysql;if(mysql.connect()){mysql.update(sql);}}// 查询离线消息
vector<string> OfflineMessageModel::query(int userid)
{// 1. 创建数据库连接// 2. 执行 SQL 语句查询离线消息// 3. 关闭数据库连接// 4. 返回查询结果char sql[1024] = {0};sprintf(sql, "select message from offlinemessage where userid = %d", userid);vector<string> vec;MySQL mysql;if(mysql.connect()){MYSQL_RES *res = mysql.query(sql);   // 数据库apiif(res!=nullptr){MYSQL_ROW row;while((row = mysql_fetch_row(res)) != nullptr){vec.push_back(row[0]); // 将查询到的消息添加到结果向量中}mysql_free_result(res); // 释放一下资源, 否则内存不断泄露}return vec;}return vec;
}

include/server/chatservice.hpp

#include <offlinemessagemodel.hpp>// 离线消息操作对象OfflineMessageModel _offlineMsg;

src/server/chatservice.cpp

//补充 点对点聊天的 离线存储业务    
//不在线, 存储离线消息_offlineMsg.insert(toid, js.dump());
//补充 登录业务, 登陆成功后, 查询是否有离线消息// 查询离线消息
vector<string> vec = _offlineMsg.query(id);
if (!vec.empty())
{response["offlinemsg"] = vec; // 离线消息  js可以直接序列化容器// 离线消息发送完毕, 删除离线消息_offlineMsg.remove(id);       
}

问题

新增了文件, 容易出现 链接错误, 因为找不到

需要把 build里面的全部删了, 重新 cmake

测试

{"msgid":1,"id":22,"password":"101010"}
{"msgid":5,"id":22,"from":"hzh","to":23,"msg":"i am hzh!hello!"}

至此, 数据库 离线消息 表已经存储了, 可以自行查看

{"msgid":1,"id":23,"password":"101010"}

至此, 数据库 离线消息 表已经 删除了

服务器异常下线

功能不完整

之前,客户端异常下线主要导致了用户状态的变化。然而,目前更常遇到的是服务器端异常,例如无法识别字符或格式错误,这些问题通常会导致服务器异常下线。

这种异常 导致 用户 状态 没改变, 所以 需要 进行完善!!

目前 仅处理 服务端 ctrl+c 的异常, 暂不处理 客户端发过来消息 不对导致的 服务器退出问题

解决核心

使用信号捕捉函数: signal------这个实际一般不推荐

(一般使用sigaction()函数)-----老师没用这个

解决步骤

捕获终止信号:使用 signal.h 来捕获 Ctrl+C 终止信号(SIGINT),并在信号处理函数中进行用户状态的重置。

编写重置函数

  • chat service 中添加 reset 方法,用来重置用户的状态。
  • reset 方法调用 user model 中的 update 方法,将所有在线(online)状态的用户状态更新为离线(offline)。

确保正确更新数据库:通过 SQL 语句 UPDATE user SET state = 'offline' WHERE state = 'online' 来批量更新数据库中用户的状态。

测试过程

  • 在正常登录和退出后,测试通过 Ctrl+C 强制结束服务器,确保所有用户的状态都被成功更新为离线(offline)。
  • 在服务器重启后,验证用户状态是否恢复正确。

低耦合性

main.cpp 仅负责信号捕获,ChatService 处理业务逻辑,UserModel 负责数据库操作

代码结构

src/server/main.cpp

使用信号捕捉

#include <signal.h>
#include "chatservice.hpp"void resetHandler(int)
{ChatService::instance()->reset();exit(0);
}//main
signal(SIGINT, resetHandler);

include/server/chatservice.hpp

    // 服务器异常退出处理, 重置用户状态函数void reset();

src/server/chatservice.cpp

// 服务器异常退出处理, 重置用户状态函数
void ChatService::reset()
{// 更新所有用户的状态----把在线用户都设置为离线_usermodel.resetState();
}

include/server/usermodel.hpp

// 重置用户状态void resetState();

src/server/usermodel.cpp

// 重置用户状态
void UserModel::resetState()
{//1. 组装 sql语句char sql[1024]={0};sprintf(sql, "update user set state='offline' where state='online'");MySQL mysql;if(mysql.connect()){mysql.update(sql);}
}

测试

{"msgid":1,"id":22,"password":"101010"}
服务器:  ctrl+c

相关文章:

施磊老师基于muduo网络库的集群聊天服务器(四)

文章目录 实现登录业务登录业务代码补全数据库接口:查询,更新状态注意学习一下里面用到的数据库api测试与问题**问题1:****问题2:** 用户连接信息与线程安全聊天服务器是长连接服务器如何找到用户B的连接&#xff1f;在业务层存储用户的连接信息多线程安全问题加锁! 处理客户端…...

Java多线程编程初阶指南

目录 一.线程基础概念 线程是什么&#xff1f; 线程与进程对比 为啥要有线程 二.线程实现方式 继承Thread类 实现Runnable接口 常规实现方式 匿名内部类写法 Lambda表达式写法&#xff08;Java8&#xff09; 对比总结 三.Thread 类及常见方法 核心功能 核心构造方…...

DB-GPT支持mcp协议配置说明

简介 在 DB-GPT 中使用 MCP&#xff08;Model Context Protocol&#xff09;协议&#xff0c;主要通过配置 MCP 服务器和智能体协作实现外部工具集成与数据交互。 开启mcp服务&#xff0c;这里以网页抓取为例 npx -y supergateway --stdio "uvx mcp-server-fetch" …...

CoT-Drive:利用 LLM 和思维链提示实现自动驾驶的高效运动预测

25年3月来自澳门大学和 MIT 的论文“CoT-Drive: Efficient Motion Forecasting for Autonomous Driving with LLMs and Chain-of-Thought Prompting”。 准确的运动预测对于安全的自动驾驶 (AD) 至关重要。本研究提出 CoT-Drive&#xff0c;这是一种利用大语言模型 (LLM) 和思…...

Flowable7.x学习笔记(十)分页查询已部署 BPMN XML 流程

前言 上一篇文章我们已经完成了流程的部署功能&#xff0c;那么下一步就是要激活流程了&#xff0c;但是我们要需要明确的指定具体要激活部署后的哪一条流程&#xff0c;所以我们先把已部署的基础信息以及具体定义信息分页查询出来&#xff0c;本文先把基础代码生成以及完成分页…...

【仓颉 + 鸿蒙 + AI Agent】CangjieMagic框架(15):NaiveExecutor

CangjieMagic框架&#xff1a;使用华为仓颉编程语言编写&#xff0c;专门用于开发AI Agent&#xff0c;支持鸿蒙、Windows、macOS、Linux等系统。 这篇文章剖析一下 CangjieMagic 框架中的 NaiveExecutor。 1 NaiveExecutor是什么&#xff1f; #mermaid-svg-u9WgSijieH1Pk0xU…...

Office文档图片批量提取工具

Office.Files.Images 是一款专注于从 Word、Excel、PPT 等 Office 文档中批量提取图片的轻量级工具&#xff0c;支持 .docx、.xlsx、.pptx 格式文件。该软件体积仅 ‌343KB‌&#xff0c;无需安装即可运行&#xff0c;通过拖拽操作实现快速解析与导出&#xff0c;尤其适合需批量…...

33-公交车司机管理系统

技术&#xff1a; 基于 B/S 架构 SpringBootMySQLvueelementui 环境&#xff1a; Idea mysql maven jdk1.8 node 用户端功能 1.首页:展示车辆信息及车辆位置和线路信息 2.模块:车辆信息及车辆位置和线路信息 3.公告、论坛 4.在线留言 5.个人中心:修改个人信息 司机端功能…...

PyCharm 初级教程:从安装到第一个 Python 项目

作为 Python 程序员&#xff0c;无论是刚入门还是工作多年&#xff0c;PyCharm 都是一个绕不开的开发工具。它是 JetBrains 出品的一款强大的 Python IDE&#xff0c;有自动补全、调试、虚拟环境支持、代码检查等等功能&#xff0c;体验比命令行 记事本舒服一百倍。 今天这篇…...

文件上传漏洞3

1. 例题:文件上传限制 1&#xff09;上传漏洞靶场介绍 项目名称: upload-labs开发语言: 使用PHP语言编写功能定位: 专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场关卡数量: 目前共21关&#xff0c;每关包含不同上传方式注意事项: 每关没有固定通关方法&#xff0c;不要自限…...

QML FontDialog:使用FontDialog实现字体选择功能

目录 引言相关阅读FontDialog基本介绍字体属性 实例演示项目结构代码实现Main.qmlmain.cpp 代码解析运行效果 总结 引言 在桌面应用程序开发中&#xff0c;字体选择是一个常见的需求。Qt Quick提供了FontDialog组件来实现这一功能。本文将介绍如何在Qt Quick应用程序中使用Fon…...

力扣刷题Day 27:环形链表(141)

1.题目描述 2.思路 创建一个结点集合&#xff0c;遍历链表&#xff0c;如果遇到已经加进集合的结点就说明链表有环。 3.代码&#xff08;Python3&#xff09; class Solution:def hasCycle(self, head: Optional[ListNode]) -> bool:node headnode_set set()while node…...

1.1软考系统架构设计师:系统架构的定义与作用 - 超简记忆要点、知识体系全解、考点深度解析、真题训练附答案及解析

超简记忆要点 定义&#xff1a;结构决策 | 抽象概念 | 多视图模型&#xff08;逻辑/物理/动态&#xff09;作用&#xff1a;解耦复杂需求 | 集成扩展 | 指导开发&#xff08;蓝图&#xff09;要素&#xff1a;构件&#xff08;原子/复合&#xff09; | 连接件&#xff08;API/…...

研发效率破局之道阅读总结(3)工程优化

研发效率破局之道阅读总结(3)工程优化 Author: Once Day Date: 2025年4月22日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 程序的艺术_Once-Day…...

metasploit(2)生成dll木马

声明&#xff01;本文章所有的工具分享仅仅只是供大家学习交流为主&#xff0c;切勿用于非法用途&#xff0c;如有任何触犯法律的行为&#xff0c;均与本人及团队无关&#xff01;&#xff01;&#xff01; 一、dll文件基本概念 DLL 是一种包含可由多个程序同时使用的代码和数…...

数据结构--并查集-高效处理连通性问题

目录 一、理论基础 &#xff08;1&#xff09;并查集的功能及实现原理 &#xff08;2&#xff09;代码模版 &#xff08;3&#xff09;模拟过程 &#xff08;4&#xff09;应用 二、基础题练习 &#xff08;1&#xff09;寻找存在的路径&#xff08;模版题&#xff09; …...

PLOG安装

Plog可以通过以下命令安装 cd ~ && git clone https://github.com/SergiusTheBest/plog.gitcd plog && mkdir buildcd build && cmake ..make && sudo make installcd ~ && sudo rm -rf ./plog若无法科学上网&#xff0c;可使用git cl…...

LeetCode 热题 100_分割等和子集(89_416_中等_C++)(动态规划)

LeetCode 热题 100_分割等和子集&#xff08;89_416&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;动态规划&#xff09;&#xff1a; 代码实现代码实现&#xff08;思路一&#xff08;动态规划&#xff0…...

WPS Office安卓版云文档同步速度与PDF转换体验测评

WPS Office安卓版是很多人常用的移动办公软件。它支持在线编辑、文档同步、格式转换等功能&#xff0c;适合手机和平板用户随时处理文档。我们用它配合谷歌浏览器打开网页文档时&#xff0c;也可以将内容快速保存到云端或转换成PDF格式使用。 先说云文档同步。在打开WPS Office…...

Eureka、LoadBalance和Nacos

Eureka、LoadBalance和Nacos 一.Eureka引入1.注册中心2.CAP理论3.常见的注册中心 二.Eureka介绍1.搭建Eureka Server 注册中心2.搭建服务注册3.服务发现 三.负载均衡LoadBalance1.问题引入2.服务端负载均衡3.客户端负载均衡4.Spring Cloud LoadBalancer1).快速上手2)负载均衡策…...

【Linux网络】构建基于UDP的简单聊天室系统

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…...

【每天一个知识点】大模型的幻觉问题

“大模型的幻觉问题”是指大语言模型&#xff08;如GPT系列、BERT衍生模型等&#xff09;在生成内容时&#xff0c;产生不符合事实或逻辑的虚假信息&#xff0c;即所谓的“幻觉”&#xff08;hallucination&#xff09;。这在诸如问答、摘要、翻译、代码生成等任务中尤其常见。…...

机器学习06-RNN

RNN&#xff08;循环神经网络&#xff09;学习笔记 一、RNN 概述 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一类以序列数据为输入&#xff0c;在序列的演进方向进行递归且所有节点&#xff08;循环单元&#xff09;按链式连接的递归神…...

[大模型]什么是function calling?

什么是function calling&#xff1f; 大模型的 ​​Function Calling​​&#xff08;函数调用&#xff09;是一种让大语言模型&#xff08;如 GPT、Claude 等&#xff09;与外部工具、API 或自定义函数交互的机制。 它的核心目的是让模型能够根据用户的需求&#xff0c;​​…...

C语言高频面试题——嵌入式系统中中断服务程序

在嵌入式系统中&#xff0c;中断服务程序&#xff08;ISR&#xff09;的设计需遵循严格的规则以确保系统稳定性和实时性。以下是对这段代码的分析及改进建议&#xff1a; 代码分析 __interrupt double compute_area (double radius) { double area PI * radius * radius; pri…...

Java高频面试之并发编程-05

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;线程有哪些调度方法&#xff1f; 在Java中&#xff0c;线程的调用方法主要包括以下几种方式&#xff0c;每种方式适用于…...

野外价值观:在真实世界的语言模型互动中发现并分析价值观

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

【Linux】47.高级IO(1)

文章目录 1. 高级IO1.1 五种IO模型1.2 高级IO重要概念1.2.1 同步通信 vs 异步通信1.2.2 阻塞 vs 非阻塞 1.3非阻塞IO1.3.1 fcntl1.3.2 实现函数SetNoBlock1.3.3 轮询方式读取标准输入1.3.4 I/O多路转接之select1.3.4.1 初识select&#xff1a;1.3.4.2 select函数原型1.3.4.3 理…...

notepad++技巧:查找和替换:扩展 or 正则表达式

notepad 有很多优点&#xff1a;多标签&#xff0c;代码高亮&#xff0c;我最喜欢的是查找和替换。 除了可以一次性查找所有打开文件&#xff0c;还可以使用 扩展 or 正则表达式。 例如&#xff1a; 去掉空行&#xff1a;正则表达式&#xff1a; ^\s*$\r\n ^ 表示行首。\s*…...

【图像标注技巧】目标检测图像标注技巧

介绍一些图像标注技巧。之前引用过别人的文章 yolo目标检测 技巧 trick 提升模型性能&#xff0c;deep research检测调研报告也可以进行参考。 拉框类的标注&#xff0c;如果你不确定哪种方法好&#xff0c;你可以把所标注区域的都剪切出来&#xff0c;然后站在屏幕一米之外眯…...