1)我有一个 std::map ,其中键是客户端 IP,值是帐户 ID。身份验证后,服务器将客户端的 ip 和它的帐户 ID 存储到此映射中,然后当服务器收到来自客户端的请求时,它会检查它的 ip 并在映射中查找它。
IP 本身是不够的:可以有多个不同的客户端从同一个 IP 连接(来自同一台计算机,或者来自 NAT 后面的不同计算机,因此您只能看到 NAT IP)。如果要基于 IP 的唯一密钥,则需要使用客户端的 IP/端口元组。
2)我有一个 std::map ,其中键是随机生成的键,值是帐户 ID。认证后,服务器为这个特定的客户端生成随机密钥,将此密钥发送给客户端,客户端保存以供进一步使用,服务器将此密钥和帐户ID存储在地图中。
这是非常危险的:是什么禁止客户端发送另一个客户端的“会话 ID”而不是他的,从而劫持另一个客户端的会话?这与您可能想要阅读的 HTTP Session Hijacking 完全相同。简而言之:如果可以避免,请不要这样做。
其他可能的解决方案:
仍然使用std::map
您可以使用您的套接字句柄作为键:它在服务器上必须是唯一的,因此不会出现混淆,并且它使您免于在每条消息中检索客户端的 IP/端口。
如果您的服务器使用旧的“每个连接一个线程”模型,那么您不必跳过这些圈。只需将您的会话数据与 Thread Local Storage 变量相关联即可。或者,几乎所有线程库都允许您将参数传递给线程,这些参数可用于将特定数据与您的线程相关联(参见下面的示例)。
如果您的服务器使用旧的“每个连接一个进程”模型(fork),那么它会更容易,每个进程都有自己的变量,因此您无需做任何特别的事情。
不幸的是,只要我们不知道您的服务器使用的模型(线程、分叉、选择、aio...?),您的问题就非常开放,因此很难给您一个明确的答案。
如果您使用的是线程模型,这(大致)是我通常的做法(C++11 线程,但任何其他线程库也可以这样做):
class ClientSession {
public:
ClientSession(int sock)
: m_sock(sock),
m_thread(&ClientSession::threadFunction, this)
{
}
private:
int m_sock;
WhateverType m_someSessionVariable;
std::thread m_thread; // the thread object should be declared last so that
// it is initialised last in the constructor, thus avoiding race conditions
// during the initialisation (you really don't want the thread to access
// your member variables if they are not yet initialised!)
static void threadFunction(ClientSession* object) {
object->threadMethod();
}
void threadMethod() {
// handle your connection
// the current ClientSession object (this) *is* your session
// put whatever you want in it, eg. m_someSessionVariable
}
};
//...
int sock_client = TEMP_FAILURE_RETRY(accept(sock_server, 0, 0));
if (sock_client >= 0)
new ClientSession(sock_client);
警告:显然这段代码是有缺陷的,它永远不会破坏 ClientSession 对象,所以它有内存泄漏,但我的意思是展示如何将线程与特定会话对象相关联,我将把它留给你来管理你的对象的生命周期取决于您的确切架构和需求。