[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[] == primary) {
return _participants[];
} else if (_participants[] == primary) {
return _participants[];
}
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;
};
[CareerCup] 8.7 Chat Server 聊天服务器的更多相关文章
- 定制的Server-Sent Events 聊天服务器
//匿名聊天服务器 //将新的消息POST到/chat地址,或者以GET形式从通一个URL获取文本或事件流 //创建一个GET请求到"/"来返回一个简单的HTML文件,这个文件包括 ...
- openfire:基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件
基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件 上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfir ...
- 基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件
原文:http://www.cnblogs.com/hoojo/archive/2013/03/29/openfire_plugin_chatlogs_plugin_.html 随笔-150 评论- ...
- HTTP 笔记与总结(9)分块传输、持久链接 与 反向 ajax(comet / server push / 服务器推技术)
反向 ajax 又叫 comet / server push / 服务器推技术 应用范围:网页聊天服务器,例如新浪微博在线聊天.google mail 网页聊天 原理:一般而言,HTTP 协议的特点是 ...
- Codeforces Beta Round #5 A. Chat Server's Outgoing Traffic 水题
A. Chat Server's Outgoing Traffic 题目连接: http://www.codeforces.com/contest/5/problem/A Description Po ...
- CodeForces.5A Chat Server's Outgoing Traffic
Chat Server's Outgoing Traffic 点我挑战提目 考察点 模拟 字符串 Time Mem Len Lang 30 0 543 c++ 题意分析 给出类似一个群的即时通讯系统, ...
- 通过python 构建一个简单的聊天服务器
构建一个 Python 聊天服务器 一个简单的聊天服务器 现在您已经了解了 Python 中基本的网络 API:接下来可以在一个简单的应用程序中应用这些知识了.在本节中,将构建一个简单的聊天服务器.使 ...
- 看完这篇包你进大厂,实战即时聊天,一文说明白:聊天服务器+聊天客户端+Web管理控制台。
一.前言 说实话,写这个玩意儿是我上周刚刚产生的想法,本想写完后把代码挂上来赚点积分也不错.写完后发现这东西值得写一篇文章,授人予鱼不如授人以渔嘛(这句话是这么说的吧),顺便赚点应届学生MM的膜拜那就 ...
- Windows Server 2003服务器无法下载.exe文件的解决方法
今天架设了一台Windows Server 2003的网站服务器,发现打开网页后无法下载网站中的.exe文件,经过研究问题得以解决,拿来做个备忘. 解决方法非常简单,只需要在IIS中,将网站属性里的执 ...
随机推荐
- hibernate取出count(*)的办法
1.定义查询语句 String sql="select count(*) from ExcelInfor";2.获取count(*)返回结果: (1)int count=In ...
- MySQL中的FEDERATED引擎
首先说明> FEDERATED存储引擎访问在远程数据库的表中的数据,而不是本地的表.这个特性给某些开发应用带来了便利,你可以直接在本地构建一个federated表来连接远程数据表,配置好 ...
- poj 2942 Knights of the Round Table 圆桌骑士(双连通分量模板题)
Knights of the Round Table Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 9169 Accep ...
- C语言关键字详解
相对于其他语言来说,C语言的关键字算是少的了.在C98中关键子总共只有32个,我们来分析一下每个关键字在C语言中它独特的作用. 1.关于数据类型的关键字 (1) char :声明字符型变量或函数 ( ...
- Python中的库使用之一 PIL
先上代码:本文主要工给自己参考,在需要的时候直接搜索查找就行了,不想看没有实际运行例子的文档,当参考完这部分还哦未能解决问题在参考PIL的相关文档! Skip to content This repo ...
- swfobject.js视频播放插件
在网页中经常会用到视频播放的功能,下面介绍一下swfobject.js的视频播放应用:html代码结构: <div id="video_content"></di ...
- 2014 UESTC 暑前集训队内赛(1) 解题报告
A.Planting Trees 排序+模拟 常识问题,将耗时排一个序,时间长的先种,每次判断更新最后一天的时间. 代码: #include <iostream> #include < ...
- UVA 11235 Frequent Values ---RMQ
大白书上的例题,具体讲解见大白书,最好用用一个Log数组直接求k,这样就是纯O(1)了 #include <iostream> #include <cstdio> #inclu ...
- SGU 180 Inversions
题意:求逆序数对数量. 思路一:暴力,O(N^2),超时. 思路二:虽然Ai很大,但是n比较小,可以离散化,得到每个Ai排序后的位置Wi,然后按照输入的顺序,每个Ai对答案的贡献是Wi-Sum(Wi- ...
- C/C++学习----使用C语言代替cmd命令、cmd命令大全
[开发环境] 物理机版本:Win 7 旗舰版(64位) IDE版本:Visual Studio 2013简体中文旗舰版(cn_visual_studio_ultimate_2013_with_upda ...