从0实现基于Linux socket聊天室-增加数据库功能-5

2023-11-04

之前更新过从0实现聊天室的4篇文章,很多粉丝朋友还是觉得内容相对简单,本文一口君会在原有代码基础上增加数据库操作功能,后续文章还会增加文件传输功能。

前面文章链接:

从0实现基于Linux socket聊天室-多线程服务器模型-1
从0实现基于Linux socket聊天室-多线程服务器一个很隐晦的错误-2
从0实现基于Linux socket聊天室-实现聊天室的登录、注册功能-3
从0实现基于Linux socket聊天室-增加公聊、私聊-4

本文需要增加数据库功能,关于数据库的基础知识点,表的创建、增删改查等操作,以及对应的库函数的使用请参考以下3篇文章:
嵌入式数据库sqlite3【基础篇】-基本命令操作,小白一看就懂

嵌入式数据库sqlite3【进阶篇】-子句和函数的使用,小白一文入门

如何用C语言操作sqlite3,一文搞懂

全部掌握后,开始进入本篇。

一. 调整目录结构

为了方便编译,现在我们将前面文章的代码结构做如下调整。

root@ubuntu:/mnt/hgfs/code/chat# tree .
.
├── chat_client
│   ├── include
│   ├── Makefile
│   ├── obj
│   │   └── Makefile
│   └── src
│       ├── client.c
│       └── Makefile
├── chat.h
├── chat_server
│   ├── bin
│   │   └── server
│   ├── data
│   ├── include
│   ├── Makefile
│   ├── obj
│   │   └── server.o
│   └── src
│       ├── Makefile
│       └── server.c
└── gcc.sh

10 directories, 15 files

最终增加了数据的文件目录如下:

peng@ubuntu:/mnt/hgfs/code/chat-sqlite$ tree .
.
├── chat_client
│   ├── include
│   ├── Makefile
│   ├── obj
│   │   └── Makefile
│   └── src
│       ├── client.c
│       └── Makefile
├── chat.h
├── chat_server
│   ├── data
│   ├── include
│   │   └── data.h
│   ├── Makefile
│   ├── obj
│   │   └── Makefile
│   └── src
│       ├── data.c
│       ├── Makefile
│       └── server.c
├── clean.sh
├── gcc.sh
├── user.db
└── 解压密码.txt

9 directories, 17 files

clean.sh 用于清除临时文件
gcc.sh 用于编译整个工程

服务端代码放置到chat_server目录下;
客户端代码放置到chat_client目录下;

数据库相关代码放在chat_server/data下。

chat.h是所有客户端和服务器都会用到的头文件,所以放置在根目录下。

后续增加功能后,新增的头文件和C文件分别添加到对应工程目录的include和src目录下即可。

二、 设计数据库表

我们之前维护的所有客户端的信息是用一个全局数组,并且没有保存功能,现在我们要把所有客户端的信息全部保存到数据库中。

数据库存储的目录

chat_server/data

数据库名:

user.db

存储用户信息的表名:

user

表user格式如下:

名称 属性 说明
name TEXT PRIMARY KEY 用户名,不能重复
passwd TEXT NOT NULL 密码
fd INT NOT NULL 套接字描述符:-1表示不在线,>0表示在线
regist INT NOT NULL 用户名是否注册:-1没有注册,1注册

三、 主要功能操作的语句及函数

数据库操作最重要的就是语句,下面讲解针对不同的功能对应的实现语句

1 创建表user

CREATE TABLE IF NOT EXISTS user(name TEXT PRIMARY KEY 	NOT NULL,passwd	TEXT	NOT NULL,fd	INT NOT NULL,regist	INT	 NOT NULL);

2 增加一个用户

客户端发送注册请求后,服务器端注册用户信息到数据库中

数据库操作语句如下:

insert into user values('一口Linux', '123456',-1, 1)

功能函数如下:

int db_add_user(char name[],char passwd[])
功能:
增加一个用户,执行该函数前需要先判断该用户名是否存在

参数:
name:用户名
passwd:密码

返回值:
-1:失败
1:成功

3 判断用户是否在线

客户端发送登陆命令后,服务器通过该函数判断该用户是否已经登陆成功

数据库操作语句如下:

select fd from user where name='一口Linux'

功能函数如下:

int db_user_if_online(char *name,char *passwd)
功能:
判断用户是否在线,该函数主要根据fd的值来判断用户是否在线

参数:
name:用户名
passwd:密码		

返回值:
1:在线
-1:不在线
-2:用户不存在

4 判断某个用户名是否注册

用户发送注册命令,服务器需要判断该用户名是否已经被注册过

数据库操作语句如下:

select regist from user where name='一口Linux'

功能函数如下:

int db_user_if_reg(char *name)
功能:
判断某个用户名是否注册过

参数:
name:用户名

返回值:
 1:注册过
-1:没有注册过

5 判断用户名密码是否正确

用户发送登陆命令,需要判断用户名密码是否正确

数据库操作语句如下:

select * from user where name='一口Linux' and passwd='123456'

功能函数如下:

int db_user_pwd_corrct(char *name,char* passwd)
功能:
判断客户端发送的用户名密码是否正确

参数:
name:用户名
passwd:密码

返回值:
 1:正确
-1:用户名或者密码不正确

6 用户上线、下线

用户登陆成功后,或者发送下线申请,或者异常掉线,需要更新数据库的状态。

数据库操作语句如下:

UPDATE  user set fd=-1 where name='一口Linux'

fd的值是套接字描述符,下线设置为-1,上线设置为对应的>0的值

功能函数如下:

int db_user_on_off(int fd,char *name,unsigned int on_off) 
功能:
更新数据库中用户的fd字段

参数:
fd:套接字描述符
name:用户名
on_off:上线还是下线

返回值:
 1:正确
-1:失败

7. 显示在线用户

用户发送显示在线用户命令后,服务器从数据库当中查找所有在线用户,并将姓名循环发送给客户端

int db_list_online_user(int fd)

四、运行结果

1.服务器启动

./server 9999

端口号设定为9999

2. 客户端注册

客户端启动

./client 127.0.0.1 9999

选择1 注册,输入用户名密码即可。

3. 用户登录

输入选项2,输入刚才注册的用户名密码,如果不一致会提示错误

登录成功:

4. 注册登录其他几个用户

注册并登录新的用户111、222、333

5. 公聊

选择选项3,即进入公聊,
用户yikou向所有用户说:hello!
在这里插入图片描述可见所有用户均收到信息。

6. 私聊

用户yikou向用户111发送信息:
 由下图可知,只有用户111收到该信息,其他用户均没有收到信息。

7. 显示在线用户

8. 查看最终数据库信息

五、代码说明

为方便读者学习增加数据库和去掉数据之间的差别,

用git维护版本。

切换到没有数据库的版本,执行下面命令即可。

git reset --hard  597330ae0a183c9db8f68b7c9f60df94f8965778

要切回有数据库的版本执行下面的命令:

git reset --hard 10bfbfaf2d09ae895313273c960ecfd84663f9fd

使用数据库后,数据的存储管理更加方便,数据类型更易于扩充,
逻辑关系也更加清晰。

 有需要的朋友抓紧下载代码运行下吧。

获得完整代码,关注公众号:一口Linux,后台回复:chat

后面一口君,会在本项目基础上再增加数据加密和文件传输功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从0实现基于Linux socket聊天室-增加数据库功能-5 的相关文章

  • 我的用例可以合并到单个查询中而不影响性能吗?

    我主要着眼于改善表现查询的内容以及是否能够解决单一查询对于我的用例之一 解释如下 涉及到2张表 Table 1 EMPLOYEE column1 column2 email1 email2 column5 column6 Table 2 E
  • 数据加密

    存储大量信用卡信息的数据库是我们刚刚完成的系统中不可避免的一部分 不过 我想要的是卡号的最终安全性 我们可以设置一种加密和解密机制 但我们自己无法解密任何给定的号码 我所追求的是一种即使在数据库级别也能保护这些信息的方法 这样任何人都无法进
  • 要做或不做:将图像存储在数据库中[重复]

    这个问题在这里已经有答案了 在 Web 应用程序的上下文中 我的前老板总是说在数据库中放置对图像的引用 而不是图像本身 我倾向于同意在数据库中存储 url 与图像本身是一个好主意 但在我现在工作的地方 我们在数据库中存储大量图像 我能想到的
  • 从 Presto 中的 JSON 列获取特定值

    我有一个带有 JSON 列的表points其中一行为 0 0 2 1 1 2 2 0 5 15 1 2 20 0 7 我想获取键的值 1 and 20 并将它们存储为别名 例如first and second在查询中 到目前为止我所做的是
  • 在 Python 中,如果我有 unix 时间戳,如何将其插入 MySQL 日期时间字段?

    我正在使用 Python MySQLDB 我想将其插入 Mysql 中的 DATETIME 字段 我该如何使用cursor execute 来做到这一点 要将 UNIX 时间戳转换为 Python 日期时间对象 请使用datetime fr
  • 更改列名称 Rails

    我有这张表 class CreateShoes lt ActiveRecord Migration def change create table shoes do t t string name t boolean leather t i
  • Dapper 在执行时挂起

    我有一个 IDb连接 sql UPDATE 表名 SET json json lastupdate SYSDATE WHERE id id var param new DynamicParameters param Add json jso
  • 导轨中的多个 DB 连接

    我正在尝试在 ROR 应用程序中连接多个数据库 我的 database yml 如下所示 在你的database yml文件中 发展 adapter mysql username root password database example
  • 如何使 cx-oracle 将查询结果绑定到字典而不是元组?

    这是我的代码 我想找到一种方法将查询结果作为字典列表而不是元组列表返回 看起来 cx oracle 通过部分文档讨论 绑定 来支持这一点 虽然我不知道它是如何工作的 def connect dsn cx Oracle makedsn hos
  • 2 同一个表的同一列上的 PostgreSQL 索引 - 冗余吗?

    我有一个带有 2 个索引的 PostgreSQL 表 其中一项指数涵盖website id and tweet idcolumns 是唯一的 B 树索引 第二个索引仅涵盖website id列 并且是非唯一索引 如果第一个索引存在 第二个索
  • 创建 MySQL 用户时使用 % 表示主机

    我的 MySQL 数据库需要两个用户 appuser 和 support 一位应用程序开发人员坚持要求我为这些用户创建四个帐户 appuser appuser localhost support support localhost 我一生都
  • 在 Python 中打开 Alteryx .yxdb 文件?

    有没有办法将 yxdb Alteryx 数据库文件 导入到 Pandas Python 中 而不使用 Alteryx 作为中间人 简短的回答是否定的 目前还不行 更长的答案 yxdb 支持的原始 C 是可以在 github 上找到 http
  • 高负载应用程序的数据库可扩展性?

    我见过一些应用程序拥有集群 Web 服务器 例如 10 到 20 个服务器 以具有可扩展性 可以在其中分发 在网络服务器之间加载 但我总是看到所有网络服务器都使用单个数据库 现在考虑任何电子商务或铁路 Web 应用程序 其中有数百万用户在任
  • 单笔交易与多笔交易[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Oracle SQL 查询日期格式

    我总是对 ORACLE SQL 查询中的日期格式感到困惑 并花几分钟时间去谷歌 有人可以向我解释当数据库表中有不同格式的日期时解决问题的最简单方法吗 例如 我有一个日期列为 ES DATE 保存的数据为 27 APR 12 11 52 48
  • “已经有一个与此命令关联的打开的 DataReader,必须先将其关闭。”

    我正在开发需要连接到另一个数据库以获取一些数据的应用程序 为此 我决定使用 SqlConnection reader 等 我需要执行一些查询 例如首先我需要获取某个用户的卡 ID 之后我需要通过该卡 ID 获取一些数据 这是我的代码 reg
  • 每次都在django查询数据库中过滤查询集吗?

    想象一下我有以下代码 qs Users objects all list for i in range 10 list append qs filter age i 这里过滤器被调用 10 次 它是连接到数据库 10 次还是第一次使用过滤器
  • jsp/servlet 从数组填充下拉框

    大家好 我正在尝试创建一个表单 允许您为某个主题创建一个实验室 它有一个下拉框 您可以在其中选择与该用户相关的主题 但是 当我去加载页面时 我收到此错误g apache jasper JasperException java lang Nu
  • Google BigQuery 底层架构

    所以我大约 10 分钟前才开始摆弄 Google BigQuery 我想知道是否有人知道他们用来存储数据的底层架构 例如 这只是他们自己的下一代 BigTable 基础设施吗 另外 他们在索引 索引重建等方面使用什么样的策略是否清楚 我只是
  • Postgres 上的 C 语言环境和 Posix 语言环境有什么区别?

    我知道 Postgres 上的数据库区域设置负责国家字符的正确顺序 正确的小写 大写等 但为什么有两种语言中立的语言环境 posix and c 它们之间有什么区别 还是只是一个中立的语言环境有两个不同的名称 UPDATE正如 Magnus

随机推荐

  • 好文推荐——无需公网IP,远程连接SQL Server数据库【内网穿透】

    文章目录 0 声明 1 前言 2 本地安装和设置SQL Server 2 1 SQL Server下载 2 2 SQL Server本地连接测试 2 3 Cpolar内网穿透的下载和安装 2 4 Cpolar内网穿透的注册 3 本地网页发布
  • python中常用的工具包

    一 Python中常用的科学计算工具包 我们最了解的科学计算工具可能是Matlab 它能进行集数值计算 可视化工具及交互于一身 可惜的是它是一个商业产品 开源方面除了GNU Octave在尝试做一个类似Matlab的工具包外 Python的
  • 【Verilog 基础】阻塞赋值和非阻塞赋值的区别

    目录 阻塞赋值 非阻塞赋值 实际工程仿真 阻塞赋值仿真 编写Verilog代码 编写测试文件代码 综合看RTL图 进行实际仿真 非阻塞赋值仿真 编写Verilog代码 编写测试文件代码 综合看RTL图 实际仿真图 总结 阻塞赋值 阻塞赋值的
  • 统计封闭岛屿的数目

    1254 统计封闭岛屿的数目 关于岛屿的相似题目 岛屿数量 二维矩阵的dfs算法 封闭岛屿数量 二维矩阵的dfs算法 统计封闭岛屿的数目 统计子岛屿 不同岛屿的数量 class MaxAreaOfIsland floodFill 算法 12
  • BaseModel(数据模型映射关系)

    import BaseModel h implementation BaseModel id initContentWithDic NSDictionary dic self super init if self self dicToObj
  • 矿场无盘服务器,七号矿场引领传输新时代

    随着时代的高速发展 Web3 0时代也即将到来 海量数据的产生是必然的 如何确保数据有足够的存储空间 保证数据的安全 这就是未来需要攻克的难点 那么 IPFS网络去中心化存储 信息加密保护 信息不能篡改等技术是现阶段发展所需的技术 With
  • javascript 的筛选方法(多种方法细解)

    filter 是一个数组方法 于创建一个新的数组 其中包含原始数组中满足指定条件的所有元素 返回满足条件的所有内容 放在新的数组里 const numbers 1 2 3 4 5 6 const evenNumbers numbers fi
  • FreeBSD下开启SSH

    ee etc inetd conf 将sshd前边的注释去掉 ee etc ssh sshd config 将PermitRootLogin yes的注释去掉 允许root登陆
  • Stm32学习(七)外部中断

    1 外部中断 1 stm32的每一个IO都可以作为外部中断输入 2 stm32的中断控制器支持19个外部中断 事件请求 线0 15 对应外部IO口的输入中断 线16 连接到PVD输出 线17 连接到RTC闹钟事件 线18 连接到USB唤醒事
  • 操作系统真相还原第0章笔记

    什么是陷入内核 应用程序处于特权级别3 操作系统内核处于特权级0 当用户程序访问系统资源时 无论是硬件 还是内核数据结构 它都需要进行系统调用 这样CPU便进入了内核态 也称为管态 内存访问为什么要分段 编译器在编译程序时 肯定要根据CPU
  • can‘t open file ‘create‘: [Errno 2] No such file or directory问题解决

    这里我提供一个思路吧 我在csdn跟哔哩哔哩都去查来着 因为完全是个小白 真的不会解决 但是他们的答案不能解决我的问题 这个是建立项目时候出的问题 这里创建的不成功 我一共修改了以下几点 有点瞎改 因为不会 1 我使用的是anaconda3
  • antd 验证cron表达式

    项目中使用了quartz 前端需要输入cron表达式并做验证 后端验证很方便 直接用CronExpression isValidExpression cronStr 验证即可 现有网上的资料 要么求大虾做cron的超强正则 要么写了一大堆j
  • pytorch中分析时间开销

    在需要计算代码前使用profiler进行声明 即可输出运行开销 from torch autograd import Variable import torch x Variable torch randn 1 1 requires gra
  • dataframe动态命名(读取不同文件并规律命名)

    读取不同的10个文件到dataframe 并需要分别命名为df 10 df 10 20 以此类推 arr 10 10 20 20 30 30 50 50 70 70 90 90 100 csv paths存储文件位置 定义一个字典d 具体如
  • Vue——vue3报错 <Suspense> slots expect a single root node.

    解决 如果有多组件嵌入时需要给每个组件一个 div 标签
  • springboot最新稳定版本、springcloud对应版本的选择

    1 登录springboot官网 查看当前最稳定版本 https spring io projects spring boot learn 可以看到目前为止最稳定的最新版本是2 4 0 2 登录springcloud官网 查看当前最新的稳定
  • 鸿蒙系统应用开发入门HelloWord(DevEco Studio怎么启动项目以及程序的运行过程)

    使用DevEco Studio新建项目之后 会自带HelloWorld 其他语言需要我们自己写 由于项目使用的模拟器不是在我们本地 而是部署在华为的服务器中 所以我们需要登录华为账号并实名认证才可以使用 登录并启动项目 DevEco Stu
  • JAX-RS (REST Web Services) 2.0 requires Java 1.6 or newer.

    maven 项目出现JAX RS REST Web Services 2 0 requires Java 1 6 or newer 错误 解决办法 这个是eclipse的bug 可见这个链接 https bugs eclipse org b
  • Eclipse中使用SVN

    我的个人博客地址 opiece me 欢迎大家的访问 1 在Eclipse里下载Subclipse插件 方法一 从Eclipse Marketplace里面下载 具体操作 打开Eclipse gt Help gt Eclipse Marke
  • 从0实现基于Linux socket聊天室-增加数据库功能-5

    之前更新过从0实现聊天室的4篇文章 很多粉丝朋友还是觉得内容相对简单 本文一口君会在原有代码基础上增加数据库操作功能 后续文章还会增加文件传输功能 前面文章链接 从0实现基于Linux socket聊天室 多线程服务器模型 1 从0实现基于