首页 > 其他分享 >集群聊天服务器

集群聊天服务器

时间:2024-08-24 16:47:46浏览次数:12  
标签:muduo 群组 sudo nginx 集群 聊天 EchoServer 服务器 net

集群聊天服务器


项目地址:Focuspresent/ChatServer (github.com)

环境搭建(基于Unbuntu20.04)

boost库安装

sudo apt install libboost-all-dev

mysql开发库安装

sudo apt install libmysqlclient-dev

muduo库安装

先需要安装cmake以及boost

sudo apt install cmake

下载安装包,并解压

wget https://github.com/chenshuo/muduo/archive/refs/tags/v2.0.2.zip
mv v2.0.2.zip muduo-2.0.2.zip
unzip muduo-2.0.2.zip

修改CMakeLists.txt

cd muduo-2.0.2
vim CMakeLists.txt
  • 找到23行的-Werror注释掉解释
  • 找到13行的option(MUDUO_BUILD_EXAMPLES "Build Muduo examples" ON)注释掉,不需要测试样例

编译,安装

# 当前在muduo-2.0.2 目录下
./build.sh
./build.sh install
cd ..

# 执行后
➜  Downloads ls
build  muduo-2.0.2  muduo-2.0.2.zip

之后,需要进入安装后的目录(位于muduo-2.0.2同一级),将头文件和库文件放到系统头文件路径和系统库文件路径,否则,使用时需要通过编译选项(-I,-L)告知编译器

# 拷贝头文件
cd build/release-install-cpp11/include
sudo mv muduo/ /usr/include

# 拷贝库文件
cd ../lib
sudo mv * /usr/local/lib

测试

#include <muduo/net/TcpServer.h>
#include <muduo/base/Logging.h>
#include <boost/bind.hpp>
#include <muduo/net/EventLoop.h>

// 使用muduo开发回显服务器
class EchoServer
{
 public:
  EchoServer(muduo::net::EventLoop* loop,
             const muduo::net::InetAddress& listenAddr);

  void start(); 

 private:
  void onConnection(const muduo::net::TcpConnectionPtr& conn);

  void onMessage(const muduo::net::TcpConnectionPtr& conn,
                 muduo::net::Buffer* buf,
                 muduo::Timestamp time);

  muduo::net::TcpServer server_;
};

EchoServer::EchoServer(muduo::net::EventLoop* loop,
                       const muduo::net::InetAddress& listenAddr)
  : server_(loop, listenAddr, "EchoServer")
{
  server_.setConnectionCallback(
      boost::bind(&EchoServer::onConnection, this, _1));
  server_.setMessageCallback(
      boost::bind(&EchoServer::onMessage, this, _1, _2, _3));
}

void EchoServer::start()
{
  server_.start();
}

void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
{
  LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
           << conn->localAddress().toIpPort() << " is "
           << (conn->connected() ? "UP" : "DOWN");
}

void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
                           muduo::net::Buffer* buf,
                           muduo::Timestamp time)
{
  // 接收到所有的消息,然后回显
  muduo::string msg(buf->retrieveAllAsString());
  LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "
           << "data received at " << time.toString();
  conn->send(msg);
}


int main()
{
  LOG_INFO << "pid = " << getpid();
  muduo::net::EventLoop loop;
  muduo::net::InetAddress listenAddr(8888);
  EchoServer server(&loop, listenAddr);
  server.start();
  loop.loop();
}

编译(muduo_net在muduo_base前面)

g++ main.cpp -lmuduo_net -lmuduo_base -lpthread -std=c++11

运行

./a.out

另启一个终端,并向端口发送数据

echo "hello world" | nc localhost 8888

显示的数据

20240815 14:23:48.762392Z  3639 INFO  pid = 3639 - main.cpp:61
20240815 14:24:01.374976Z  3639 INFO  TcpServer::newConnection [EchoServer] - new connection [EchoServer-0.0.0.0:8888#1] from 127.0.0.1:34428 - TcpServer.cc:80
20240815 14:24:01.375027Z  3639 INFO  EchoServer - 127.0.0.1:34428 -> 127.0.0.1:8888 is UP - main.cpp:42
20240815 14:24:01.375066Z  3639 INFO  EchoServer-0.0.0.0:8888#1 echo 12 bytes, data received at 1723731841.375035 - main.cpp:53
20240815 14:24:10.038320Z  3639 INFO  EchoServer - 127.0.0.1:34428 -> 127.0.0.1:8888 is DOWN - main.cpp:42
20240815 14:24:10.038368Z  3639 INFO  TcpServer::removeConnectionInLoop [EchoServer] - connection EchoServer-0.0.0.0:8888#1 - TcpServer.cc:109

nginx 配置tcp负载均衡

源码安装

  1. 安装
➜  Downloads mkdir nginx
➜  Downloads cd nginx 
➜  nginx wget https://nginx.org/download/nginx-1.26.2.tar.gz 
➜  nginx tar -zvxf nginx-1.26.2.tar.gz
# 需要什么依赖,就去装
➜  nginx-1.26.2 ./configure --with-stream 
➜  nginx-1.26.2 make 
➜  nginx-1.26.2 sudo make install
➜  nginx-1.26.2 cd /usr/local/nginx 
➜  nginx cd conf
# 修改配置文件
➜  conf sudo vim nginx.conf 
  1. 部分配置文件
stream {
    upstream MyServer {
      server 127.0.0.1:9001 weight=1;
    	server 127.0.0.1:9002 weight=1;
    }
    
    server {
    	listen 9000;
    	proxy_pass MyServer;
    	tcp_nodelay on;
    }
}

nginx需要的命令

# 启动
sudo /usr/local/nginx/sbin/nginx
# 停止
sudo /usr/local/nginx/sbin/nginx -s stop
# 平滑加载(重新读取配置文件)
sudo /usr/local/nginx/sbin/nginx -s reload

redis

redis环境

sudo apt install redis-server

redis开发库

➜  Downloads git clone https://github.com/redis/hiredis.git
➜  Downloads cd hiredis 
➜  hiredis git:(master) make
➜  hiredis git:(master) sudo make install
# 如果之后hiredis链接失败
sudo ldconfig /usr/local/lib

数据库设计

数据库名(chat)

  1. 用户表(users)
列名 类型 描述 约束
id int 用户id 主键,自增
username varchar(32) 用户名 唯一,非空
password varchar(32) 用户密码 非空
state enum('offline','online') 是否在线 默认是'offline'
  1. 好友表(friends)
列名 类型 描述 约束
userid int 用户id 非空,联合主键
friendid int 好友id 非空,联合主键
state enum('pass','unverify') 这条好友消息的状态 默认是'unverify'
  1. 离线消息表(offlinemessages)
列名 类型 描述 约束
userid int 用户id 非空,普通索引
offlinemessage varchar(512) 离线的消息 非空
  1. 群组表(groups)
列名 类型 描述 约束
id int 群组id 主键,自增
groupname varchar(64) 群组名 唯一,非空
groupdesc varchar(128) 群组描述
  1. 群组用户表(groupusers)
列名 类型 描述 约束
groupid int 群组id 非空,联合主键
userid int 用户id 非空,联合主键
role enum('owner','admin','normal') 用户在群组中的角色 默认是'normal'

项目架构

├── bin
├── include
│   ├── client
│   └── server
│       ├── db
│       └── model
├── lib
├── src
│   ├── client
│   └── server
│       ├── db
│       └── model
├── test
└── thirdparty
    └── jsoncpp

服务端开发

网络层

基于muduo开发的网络类,可以根据事件的发生,调用先前注册好的回调函数,尤其是连接以及处理消息,处理消息可以调用业务类先前注册好的回调函数,根据消息类型进行处理,使用的是json类型

业务层

业务类,主要负责业务层回调函数的实现

登录

凭借先前注册的得到的账号以及账号密码,向服务端发起登录请求,处理后,会返回错误码以及相关信息

注册

用户输入账户名(唯一)以及账号密码(非空),向服务端发起注册请求,处理后,会返回账号,需要记住账号

点对点聊天

该业务没有好友限制,只需要两个客户的账号就行,假如接受端不在线,接受端的信息会被存储到离线消息中,等待接受端上线后,存储在数据库中的离线消息会被清空

添加好友

  1. 添加好友请求

一个客户向另一个客户发起添加好友请求,需要对方的账号即可,然后由服务端处理,转发给对方,等待对方同意

  1. 添加好友验证

接受到好友请求的客户,可以选择通过或者不通过,通过后,两方的好友列表(服务端)都会新增对方的信息,不通过则没有

群组聊天

  1. 创建群组

需要由客户端填写群组名(唯一)和群组描述,向服务端发起请求,成功后会返回群组号

  1. 添加群组

只需填写群组号即可,向服务端发起请求,不需要其他人的验证

  1. 群组聊天

向某个群组号填写发送的信息,向服务端发起请求,由服务端来转发除发出者之外的所有群员,离线的群员,消息会存储在离线消息表

刷新

由客户端发起,向服务端更新与当前客户相关的信息,比如,好友状态以及群组状态等

客户端开发

多线程程序,主线程负责读取用户的输入,封装成json数据,并向服务器发出请求,子线程负责读取服务端的响应,以及解析json数据,并把相应的数据打印在界面上

  1. 启动后
*****************************
        login: 1
        register: 2
        exit: 3
*****************************
  1. 登录后
******主界面******
******命令列表******
groupchat:群组聊天groupchat:groupid:msg
creategroup:创建群组creategroup:groupname:groupdesc
addgroup:添加群组addgroup:groupid
verifyfriend:验证好友请求verifyfriend:to:[y/n]
addfriend:发送添加好友请求addfriend:to
logout:退出登录
show:显示当前登录的用户信息
refresh:刷新信息refresh
chat:点对点聊天chat:to:msg
help:显示支持的命令

遇到的问题

vscode的cmake插件使用

  • 描述

本来想使用vscode的cmake插件的智能提示,发现在CMakelists.txt下没有智能提示,并且侧边栏右击后,无法展示cmake插件的具体信息

  • 解决方法

没有智能提示,是没有配置vscode的配置下的cmake路径,配置.vscode/settings.json文件中的cmake.cmakePath即可
无法显示插件,是因为我之前使用了Makefile Tools插件,将其禁用即可

mysql开发库的使用

  • 描述

在测试查询不存在的账号或者群组时,服务端异常退出

  • 解决方法

这是我之前代码的缺陷之处,只对MYSQL_RES*进行了成功判断,然后使用mysql_fetch_row()读取返回结果,但其实,成功了也有可能是空行,所以使用mysql_fetch_row()读取出来的MYSQL_ROW也要进行空指针判断,不是空指针,才能读取到数据

参考文章

  1. C++ muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装
  2. 施磊老师相关视频
  3. Mysql教程
  4. Nginx安装教程
  5. Redis教程

标签:muduo,群组,sudo,nginx,集群,聊天,EchoServer,服务器,net
From: https://www.cnblogs.com/ChangSi/p/18377889

相关文章

  • awk打印除某数据项/某列数/某些列数之外其它列数据的实现以及Twemproxy(redis集群方案
    一、awk打印除某数据项/某列数/某些列数之外其它列数据的实现        偶尔碰到一个需求,我需要使用awk打印数据,但是只需要打印某列之后的其它列,比如我只要第2列及之后的所有数据,如何实现呢?实际很简单:#将$1置成空,然后打印即可awk'{$1="";print}'filepathawk'{$1......
  • QT中通过Tcp协议的多线程的文件传输(服务器)
    首先新建一个项目命名为SendClientSever因为要进行网络通信,在pro文件的第一行代码中添加network 一、窗口设计拖一个Widget里面放入label,lineEdit,pushbutton,名称如图修改程序设计子线程recvfile类新建一个类用来执行子线程将新建的类的头文件、recvfie.h文件和.cp......
  • 买了服务器后如何正确挂载数据盘|什么是系统盘,什么是数据盘
    一、前言我们买了服务器后,一般会再买一个数据盘,如果没有数据盘,万一服务器系统出现问题后数据丢失就完了,什么数据都没了,所以为了避免意外的发生,我们通常会再买一个数据盘如上图,我就在阿里云上买了一个服务器,同时又买了一个数据盘,买完之后,我们要把这个数据盘挂载到服务器上......
  • 阿里云服务器很久未用,服务访问异常
    很久(大概一两个月)都没在使用自己的个人阿里云服务器,当自己再次访问时,竟然报错无法访问,这让自己很是意外!! 然后自己开始排查问题。登录服务器查看docker服务,发现全部正常。 可是当自己打算重新启动时发现问题,竟然无法重启,这就很奇怪了,服务不都好好的嘛,怎么就不能重启呢。......
  • 一文带你读懂反向代理服务器
    文章目录一、什么是反向代理?二、反向代理的主要特点2.1负载均衡2.2隐藏IP2.3响应加速2.4过滤非法请求三、反向代理的应用场景3.1负载均衡3.2SSL/TLS终止3.3日志记录3.4URL重写3.5API网关3.6CDN服务四、区分反向代理和正向代理4.1从工作原理上4.2从安全性上......
  • 聊天器人时代:AI智能客服助力企业转型升级
    近年来,随着人工智能技术的不断发展,越来越多的企业开始采用智能客服系统来提升客户服务质量和效率。这种新型的客服模式不仅可以为企业节省人成本,还可以实现24小时全天候在线服务,为客户提供更加便捷、快捷的咨询和解决方案AI智能客服系统主要通过聊天器人技术实现。聊天器人是一......
  • 从百度网盘中下载文件到linux服务器
    前提:先安装python环境1.安装包pipinstallbypy2.认证(第一次连接需要认证)bypyinfo 3.浏览器中打开,复制授权码,enter输入 4.认证成功后,在网盘中的“我的应用数据”目录下看到bypy目录,将要传输的数据放入bypy文件夹中。5.下载文件或者下载文件夹bypydownfile123ata.zi......
  • 配置PXE预启动执行环境:使用PXE装机服务器网络引导装机
    文章目录PXE概述PXE批量部署的优点基本的部署过程搭建的前提条件搭建配置PXE装机服务器1.准备CentOS7安装源(YUM仓库)2.安装并启用TFTP服务3.安装并启用DHCP服务4.准备Linux内核和初始化镜像文件5.准备PXE引导程序6.安装FTP服务并准备CentOS7安装......
  • wiz 为知笔记服务器 docker 跨服务器迁移爬坑指北
    本文主要是介绍wiz为知笔记服务器docker从旧服务器迁移到新服务器的步骤以及问题排查。旧服务器升级wizdocker目的:保持和新服务器拉取的镜像版本一致。官方只留了wizdocker镜像最新版,拉取不了旧版本镜像,所以先升级旧服务器上的wizdocker。升级方法dockerstopwiz......
  • wiz 为知笔记服务器 docker 跨服务器迁移爬坑指北
    本文主要是介绍wiz为知笔记服务器docker从旧服务器迁移到新服务器的步骤以及问题排查。旧服务器升级wizdocker目的:保持和新服务器拉取的镜像版本一致。官方只留了wizdocker镜像最新版,拉取不了旧版本镜像,所以先升级旧服务器上的wizdocker。升级方法dockerstopwiz......