C++群聊系统

    技术2022-07-11  71

    目录

    项目背景成品展示 项目简介需求分析客户端功能性需求服务端功能性需求 功能分解实现MsgPool类 存储用户发送的信息ChatServer类 服务端处理ChatClient类 客户端处理UserInfo类 用户信息UserManager类 用户管理loginConnect类 保存TCP socketChatWindow类 用户绘制边框 开发环境项目问题源码链接

    项目背景

    如今各种各样的聊天工具层出不穷,功能繁多,想通过自己能力,实现一个简单的群聊工具。

    成品展示

    如果不想要用户列表旁边的数字 则在ChatWindow类中 将RunUserList函数的for循环中 将 +std::to_string(UserList.size())去掉即可

    项目简介

    Linux下的群聊系统,TCP进行账号的注册与登陆,UDP进行信息的群发。运用CS模型

    需求分析

    客户端功能性需求

    1.完成用户注册,登陆请求发送 2.将用户发送的信息发送到服务端 3.获取当在线用户的信息

    服务端功能性需求

    1.获取客户端发送信息 2.定义生产线程与消费线程 3.实现用户注册登陆 4.生成数据存在数据池 5.从数据池获取数据进行群发

    功能分解实现

    MsgPool类 存储用户发送的信息

    数据池:用于存储用户发送的信息 线程安全的队列 + 2个接口 线程安全: 同步:条件变量 互斥:互斥锁 队列: STL::queue //构造函数 MsgPool() //析构函数 ~MsgPool() Public: //将信息存入队列中 void PushMsgToPool(std::string& msg); //将信息从队列中取出——> msg为出参 void PopMsgFromPool(std::string* msg); Private: //判断队列是否满了 bool IsFull() Private: std::queue<std::string> MsgQue_; //队列容量 size_t capacity_; //互斥锁 pthread_mutex_t MsgQueLock_; //消费者条件变量 pthread_cond_t SynComQue_; //生产者条件变量 pthread_cond_t SynProQue_;

    ChatServer类 服务端处理

    //处理信息的接口 private: //生产线程 static void* ProducetMsgStart(void* arg); 内部调用RevMsg()接收信息 //消费线程 static void* ConsumeMsgStart(void* arg); 内部调用BroadcastMsg()群发信息 //接收信息 void RevMsg() //广播接口 void BroadcastMsg() //消息发送给单个客户端 void SendMsg(const std::string& msg, struct sockaddr_in& cliaddr, socklen_t& len) private: int UdpSock_; //Udp套接字与端口 int UdpPort; //数据池 Msgpool* MsgPool_; //tcp处理注册,登陆请求 int TcpSock_; int TcpPort_; //用户管理 userManager* UserMana_; }

    ChatClient类 客户端处理

    #客户端 注册标识——>注册请求——>服务端 登录标识——>登陆请求——>服务端 退出登录表识——>退出登录请求——>服务端 ChatClient { //构造函数 ChatClient(std::string SvrIp =192.168.79.128) //析构函数 ~ChatClient() //初始化UDP void Init() //创造TCP socket 并进行填充 bool Connect2Server() //注册函数 bool Register() //登陆函数 bool Login() //udp数据发送 bool SendMsg(const std::string& msg) //udp数据获取 bool RecvMsg(std::string* msg) //获取当前登录的用户 MySelf& GetMySelf() //将当前用户放入登录用户数组中 void PushUser(std::string& user_info) //获取登录用户 std::vector<std::string>& GetOnlieUser() private: int UdpSock_; int UdpPort_; int TcpSock_; int TcpPort_; //保存服务端ip std::string StrIp_; //客户端信息 MySelf me_; //保存在线用户 std::vector<std::string> OnlineUser; } struct MySelf { std::string NiceName_; std::string School_; std::string Passed_; uint_t UserId_; }

    UserInfo类 用户信息

    保存用户NickName. School. udp客户端信息。用户状态 public: //注册和登录使用TCP 不需要保存,等到第一次使用UDP发送消息保存UDP UserInfo(const std::string& NickName, const std::string& School, const uint32_t UserId, const std::string& Passed); //设置用户状态 void SetUserStatus(void Status); //获取密码 std::string& GetPasswd(); //获取当前用户状态 int& GetUserStatus(); void SetCliAddr(const struct sockaddr_in& CliAddrInfo); void SetCliAddrLen(const socklen_t& CliAddrlen); Private: std::string NickName_; std::string School_; //用户Id ———>用于返回给用户 uint_32_t UserId_; std::string Passed_; //保存 udp客户端地址信息 struct sockaddr_in CliAddr_; socklen_t CliAdddren_; //保存当前用户状态 int UserStatus_;

    UserManager类 用户管理

    用户管理类:保存在线用户信息和注册用户信息。要分配的用户id UserManager { UserManager(); ~UserManager(); //注册接口 int Register(const std::string& NickName, const std::string& School, const std::string& Passed, uint32_t* UserId); //登录接口 int Login(const uint32_t& UserId, const std::string& Passed); //登出接口 int LoginOut(); //判断是否已经登录 bool IsLogin(uint32_t UserId, const struct sockaddr_in& cliudp, const socklen_t& cliaddrlen); //获取在线用户列表 void GetOnlineUserInfo(std::vector<UserInfo>* vectorized); private: //保存注册用户信息 std::unordered_map<uint32_t, UserInfo> UserMap_; //互斥锁 pthread_mutex_t Lock_; //保存在线用户信息 std::vector<UserInfo> OnlineUserVec_; //预分配用户id uint32_t PerpareUserId_; }

    loginConnect类 保存TCP socket

    用于保存链接的tcp sock 和 chatserver指针 并将注册 用户状态等信息的结构体放入这个文件中 //注册信息 Struct RegInfo { char NiceName_[15]; char School_[20]; char Passed_[20]; } //登陆信息 struct LoginInfo { uint32_t UserId_; char Passed_[20]; } //用户状态 enum UserStatus { //注册失败 REGFAILED=0, //成功 REGISTERED, //登陆失败 LOGINFAILED, // LOGINED }; //应答信息 struct ReplyInfo { //当前状态 int status; uint32_t UserId_; } Public: LoginConnect(int sock, void* server) int GetTcpSock() void* GetServer() Private: int Sock_; //保存ChatServer的实例化指针 void* Server_;

    ChatWindow类 用户绘制边框

    public: ChatWindow() ~ChatWindow() //绘制顶部边框 void DrawHeader() //绘制输出框 void DrawOutput() //绘制用户列表框 void DrawUserList() //绘制输入框 void DrawInput() //将字符串输出到对应框中 void PutStringToWin(WINDOW* win, int y, int x, const std::string& msg) //从对应框中获取字符串 void GetStringFromWin(WINDOW* win, std::string* Data) //运行各个边框 static void RunHeader(ChatWindow* cw) static void RunOutput(ChatWindow* cw, ChatClient* cc) static void RunInput(ChatWindow* cw, ChatClient* cc) static void RunUserList(ChatWindow* cw, ChatClient* cc) static void* DrawWindow(void* arg) //运行 void Start(ChatClient* chatcli) private: WINDOW* header_; WINDOW* output_; WINDOW* input_; WINDOW* user_list_; std::vector<pthread_t> threads_; pthread_mutex_t lock_;

    开发环境

    Linux version 3.10.0-514.el7.x86_64 gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)

    项目问题

    1.互相发送的信息只能是英文,中文则会出现乱码问题 2.项目中没有对退出进行编写,所以右侧人栏则没有人退出之后减少现象 3.数据存储在服务端,并未存储在数据库中,服务端退出则所有数据消失 4.只能生成一个群聊房,无法开启多个

    源码链接

    位于Gitee上的源码链接 位于GitHub上的源码链接

    Processed: 0.013, SQL: 9