[CareerCup] 8.7 Chat Server 聊天服务器

简介:

8.7 Explain how you would design a chat server. In particular, provide details about the various backend components, classes, and methods. What would be the hardest problems to solve?

这个简易的聊天服务器功能十分的有限,毕竟只是针对面试题的,谁也无法在面试的有限时间内设计出像QQ那样强大的聊天工具,所以只是实现一些基本的功能即可,根据书上所述,包括如下功能:

1. 登陆和登出

2. 添加请求(发送,接受,和拒绝)

3. 更显一个状态消息

4. 建立私聊和群聊

5. 添加信息到私聊和群聊

enum UserStatusType { Offline, Away, Idle, Available, Busy };
enum RequestStatus { Unread, Read, Accepted, Rejected };

class Date {
public:
    Date() {}
    Date(int m, int d, int y): _month(m), _day(d), _year(y) {}

private:
    int _month, _day, _year;
};

class Message {
public:
    Message(string content, Date *date): _content(content), _date(date) {} 
    string getContent() { return _content; }
    Date* getDate() { return _date; }

private:
    string _content;
    Date *_date;
};

class Conversation {
public:
    vector<Message*> getMessages() { return _messages; }
    bool addMessage(Message *m) { 
        _messages.push_back(m);
        return true;
    } 
    int getId() { return _id; }

protected:
    vector<User*> _participants;
    int _id;
    vector<Message*> _messages;
};

class GroupChat: public Conversation {
public:
    void removeParticipant(User *user) {
        for (vector<User*>::iterator it = _participants.begin(); it != _participants.end(); ++it) {
            if (*it == user) _participants.erase(it);
        }
    } 
    void addParticipant(User *user) {
        _participants.push_back(user);
    } 
};

class PrivateChat: public Conversation {
public:
    PrivateChat(User *user1, User *user2) {
        _participants.push_back(user1);
        _participants.push_back(user2);
    } 
    User* getOtherParticipant(User *primary) {
        if (_participants[0] == primary) {
            return _participants[1];
        } else if (_participants[1] == primary) {
            return _participants[0];
        }
        return nullptr;
    } 
};

class AddRequest {
public:
    AddRequest(User *from, User *to, Date *date): _fromUser(from), _toUser(to), _date(date) {
        _status = RequestStatus::Unread;
    } 
    void setStatus(RequestStatus status) { _status = status; }
    RequestStatus getStatus() { return _status; }
    User* getFromUser() { return _fromUser; }
    User* getToUser() { return _toUser; }
    Date* getDate() { return _date; }

private:
    User *_fromUser;
    User *_toUser;
    Date *_date;
    RequestStatus _status;
};

class UserStatus{
public:
    UserStatus(UserStatusType type, string message): _type(type), _message(message) {} 
    UserStatusType getStatusType() { return _type; }
    string getMessage() { return _message; }

private:
    string _message;
    UserStatusType _type;
};

class UserManager;

class User {
public:
    User(int id, string accountName, string fullName): _id(id), _accountName(accountName), _fullName(fullName) {}
    bool sendMessageToUser(User *to, string content) {
        PrivateChat *chat = _privateChats[to->getId()];
        if (chat == nullptr) {
            chat = new PrivateChat(this, to);
            _privateChats[to->getId()] = chat;
        }
        Message *message = new Message(content, new Date());
        return chat->addMessage(message);
    } 
    bool sendMessageToGroupChat(int id, string content) {
        GroupChat *chat = _groupChats[id];
        if (chat != nullptr) {
            Message *message = new Message(content, new Date());
            return chat->addMessage(message);
        }
        return false;
    } 
    void setStatus(UserStatus *status) { _status = status; }
    UserStatus* getStatus() { return _status; };
    bool addContact(User *user) {
        if (_contacts.find(user->getId()) != _contacts.end()) {
            return false;
        } else {
            _contacts[user->getId()] = user;
            return true;
        }
    } 
    void receivedAddRequest(AddRequest *req) {
        int senderId = req->getFromUser()->getId();
        if (_receivedAddRequests.find(senderId) == _receivedAddRequests.end()) {
            _receivedAddRequests[senderId] = req;
        }
    } 
    void sentAddRequest(AddRequest *req) {
        int receiverId = req->getFromUser()->getId();
        if (_sentAddRequests.find(receiverId) == _sentAddRequests.end()) {
            _sentAddRequests[receiverId] = req;
        }
    } 
    void removeAddRequest(AddRequest *req) {
        if (req->getToUser() == this) {
            for (unordered_map<int, AddRequest*>::iterator it = _receivedAddRequests.begin(); it != _receivedAddRequests.end(); ++it) {
                if (it->second == req) _receivedAddRequests.erase(it);
            }
        } else if (req->getFromUser() == this) {
            for (unordered_map<int, AddRequest*>::iterator it = _sentAddRequests.begin(); it != _sentAddRequests.end(); ++it) {
                if (it->second == req) _sentAddRequests.erase(it);
            }
        }
    } 
    void requestAddUser(string accountName) {
        UserManager::getInstance()->addUser(this, accountName);
    } 
    void addConversation(PrivateChat *conversation) {
        User *otherUser = conversation->getOtherParticipant(this);
        _privateChats[otherUser->getId()] = conversation;
    }
    void addConversation(GroupChat *conversation) {
        _groupChats.push_back(conversation);
    }
    int getId() { return _id; }
    string getAccountName() { return _accountName; };
    string getFullName() { return _fullName; }

private:
    int _id;
    UserStatus *_status = nullptr;
    unordered_map<int, PrivateChat*> _privateChats;
    vector<GroupChat*> _groupChats;
    unordered_map<int, AddRequest*> _receivedAddRequests;
    unordered_map<int, AddRequest*> _sentAddRequests;
    unordered_map<int, User*> _contacts;
    string _accountName;
    string _fullName;
};
class UserManager {
public:
    static UserManager* getInstance() {
        if (_instance == nullptr) _instance = new UserManager();
        return _instance;
    }
    void addUser(User *fromUser, string toAcountName) {
        User *toUser = _usersByAccountName[toAcountName];
        AddRequest *req = new AddRequest(fromUser, toUser, new Date());
        toUser->receivedAddRequest(req);
        fromUser->sentAddRequest(req);
    } 
    void approveAddRequest(AddRequest *req) {
        req->setStatus(RequestStatus::Accepted);
        User *from = req->getFromUser();
        User *to = req->getToUser();
        from->addContact(to);
        to->addContact(from);
    } 
    void rejectAddRequest(AddRequest *req) {
        req->setStatus(RequestStatus::Rejected);
        User *from = req->getFromUser();
        User *to = req->getToUser();
        from->removeAddRequest(req);
        to->removeAddRequest(req);
    }
    void userSignedOn(string accountName) {
        User *user = _usersByAccountName[accountName];
        if (user != nullptr) {
            user->setStatus(new UserStatus(UserStatusType::Available, ""));
            _onlineUsers[user->getId()] = user;
        }
    } 
    void userSignedOff(string accountName) {
        User *user = _usersByAccountName[accountName];
        if (user != nullptr) {
            user->setStatus(new UserStatus(UserStatusType::Offline, ""));
            for (unordered_map<int, User*>::iterator it = _onlineUsers.begin(); it != _onlineUsers.end(); ++it) {
                if (it->first == user->getId()) _onlineUsers.erase(it);
            }
        }
    } 
private:
    static UserManager *_instance;
    unordered_map<int, User*> _usersById;
    unordered_map<string, User*> _usersByAccountName;
    unordered_map<int, User*> _onlineUsers;
};

本文转自博客园Grandyang的博客,原文链接:聊天服务器[CareerCup] 8.7 Chat Server ,如需转载请自行联系原博主。

相关文章
|
1月前
|
存储 人工智能 自然语言处理
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
ChatMCP 是一款基于模型上下文协议(MCP)的 AI 聊天客户端,支持多语言和自动化安装。它能够与多种大型语言模型(LLM)如 OpenAI、Claude 和 OLLama 等进行交互,具备自动化安装 MCP 服务器、SSE 传输支持、自动选择服务器、聊天记录管理等功能。
198 15
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
|
2月前
|
Ubuntu 网络协议 关系型数据库
超聚变服务器2288H V6使用 iBMC 安装 Ubuntu Server 24.04 LTS及后续系统配置
【11月更文挑战第15天】本文档详细介绍了如何使用iBMC在超聚变服务器2288H V6上安装Ubuntu Server 24.04 LTS,包括连接iBMC管理口、登录iBMC管理界面、配置RAID、安装系统以及后续系统配置等步骤。
326 4
|
3月前
|
网络协议 Ubuntu Linux
gpg从公钥服务器接收失败(gpg: keyserver receive failed: Server indicated a failure)
通过上述步骤,大多数情况下应该能够解决GPG从公钥服务器接收失败的问题。如果问题依旧存在,可能需要进一步调查与公钥服务器相关的更深层次的技术问题,或者考虑在相关社区论坛寻求帮助。
682 1
|
3月前
|
网络协议 Windows
Windows Server 2019 DHCP服务器搭建
Windows Server 2019 DHCP服务器搭建
|
3月前
|
网络协议 定位技术 Windows
Windows Server 2019 DNS服务器搭建
Windows Server 2019 DNS服务器搭建
126 1
|
3月前
|
网络协议 文件存储 Windows
Windows Server 2019 FTP服务器搭建
Windows Server 2019 FTP服务器搭建
124 0
|
10天前
|
弹性计算 数据挖掘 应用服务中间件
阿里云轻量应用服务器68元与云服务器99元和199元区别及选择参考
目前阿里云有三款特惠云服务器,第一款轻量云服务器2核2G68元一年,第二款经济型云服务器2核2G3M带宽99元1年,第三款通用算力型2核4G5M带宽199元一年。有的新手用户并不是很清楚他们之间的区别,因此不知道如何选择。本文来介绍一下它们之间的区别以及选择参考。
236 87
|
3天前
|
存储 弹性计算 应用服务中间件
阿里云轻量应用服务器出新品通用型实例了,全球26个地域可选
近日,阿里云再度发力,推出了首款全新升级的轻量应用服务器——通用型实例。这款服务器实例不仅标配了200Mbps峰值公网带宽,更在计算、存储、网络等基础资源上进行了全面优化,旨在为中小企业和开发者提供更加轻量、易用、普惠的云计算服务,满足其对于通用计算小算力的迫切需求。目前,这款新品已在全球26个地域正式上线,为全球用户提供了更加便捷、高效的上云选择。
|
20天前
|
机器学习/深度学习 人工智能 PyTorch
阿里云GPU云服务器怎么样?产品优势、应用场景介绍与最新活动价格参考
阿里云GPU云服务器怎么样?阿里云GPU结合了GPU计算力与CPU计算力,主要应用于于深度学习、科学计算、图形可视化、视频处理多种应用场景,本文为您详细介绍阿里云GPU云服务器产品优势、应用场景以及最新活动价格。
阿里云GPU云服务器怎么样?产品优势、应用场景介绍与最新活动价格参考
|
19天前
|
存储 运维 安全
阿里云弹性裸金属服务器是什么?产品规格及适用场景介绍
阿里云服务器ECS包括众多产品,其中弹性裸金属服务器(ECS Bare Metal Server)是一种可弹性伸缩的高性能计算服务,计算性能与传统物理机无差别,具有安全物理隔离的特点。分钟级的交付周期将提供给您实时的业务响应能力,助力您的核心业务飞速成长。本文为大家详细介绍弹性裸金属服务器的特点、优势以及与云服务器的对比等内容。

热门文章

最新文章