如何避免服务器的多个线程向客户端发送数据的竞态条件?c++
How would one avoid race conditions from multiple threads of a server sending data to a client? C++
我正在跟随youtube上一个使用winsock和c++构建聊天程序的教程。不幸的是,本教程从未考虑过竞态条件,这导致了许多问题。
教程让我们在每次新客户端连接到聊天服务器时打开一个新线程,该线程将处理来自该单个客户端的接收和处理数据。
void Server::ClientHandlerThread(int ID) //ID = the index in the SOCKET Connections array
{
Packet PacketType;
while (true)
{
if (!serverptr->GetPacketType(ID, PacketType)) //Get packet type
break; //If there is an issue getting the packet type, exit this loop
if (!serverptr->ProcessPacket(ID, PacketType)) //Process packet (packet type)
break; //If there is an issue processing the packet, exit this loop
}
std::cout << "Lost connection to client ID: " << ID << std::endl;
}
当客户端发送消息时,线程将处理它并发送它,首先发送数据包类型,然后发送消息/数据包的大小,最后发送消息。
bool Server::SendString(int ID, std::string & _string)
{
if (!SendPacketType(ID, P_ChatMessage))
return false;
int bufferlength = _string.size();
if (!SendInt(ID, bufferlength))
return false;
int RetnCheck = send(Connections[ID], _string.c_str(), bufferlength, NULL); //Send string buffer
if (RetnCheck == SOCKET_ERROR)
return false;
return true;
}
当两个线程(两个独立的客户端)同时尝试向同一个ID发送消息时,就会出现这个问题。(同样是第三个客户端)。一个线程可能向客户端发送int包类型,因此客户端现在准备接收int,但随后第二个线程发送一个字符串。(因为线程假设客户端正在等待)。客户端无法正确处理,导致程序不可用。
我该如何解决这个问题?
我有一个解决方案:它们将设置一个输入值,而不是允许每个线程单独执行服务器命令。主服务器线程将循环遍历来自每个线程的所有输入值,然后逐一执行命令。
但是我不确定这不会有自己的问题…如果客户机在单个服务器循环的时间范围内发送多条消息,则只发送其中一条消息(因为新消息将覆盖前一条消息)。当然,有一些方法可以解决这个问题,比如输入数组或更快的循环,但它仍然会带来一个问题。
我想到的另一个问题是,具有较低ID的客户端最终总是在每个循环中首先发送消息。这并不是什么大问题,但如果存在一种情况,比如在一款琐事游戏中,两名客户在同一循环中输入正确答案,那么拥有较低ID的客户每次都会说出"第一个"答案。
提前感谢。
如果所有I/O都是通过中央服务器处理的,那么一个简单(但肯定不是很优雅)的解决方案是在每个客户机的I/O机制周围创建一个屏障。在最简单的情况下,这可能只是一个互斥对象。将该屏障与每个客户端关联,并且每当有人想要向该客户端发送某些内容(完整的消息)时,锁定该屏障。在处理完整消息时解锁它。这样,一次只有一个客户端可以实际地向另一个客户端发送一些内容。在c++ 11中,参见std::mutex
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 嵌套在类中时无法设置成员数据
- 初始化数据成员取决于构造函数中的条件
- C 模板:如何根据数据类型有条件编译不同的代码
- 如何根据一组规则/条件检查一组数据以进行分类
- 会读取的种族条件会同时改变读取和书写的数据
- 确定是否将对象分配在静态内存块中(还是如何避免数据竞赛条件)
- 插入最有效的数据结构,然后使用不同的条件进行排序
- 具有混合数据类型的条件运算符
- BitBlt仅在特定条件下复制部分数据
- 减少大数据的条件语句
- 如果数据类型不同,则进行条件编译
- 我正在尝试清除数据文件中具有某些条件的特殊字符,但这些条件不满足
- c++为不符合条件的数据输入创建循环
- 使用模板有条件地生成c++类的数据成员
- 如何避免服务器的多个线程向客户端发送数据的竞态条件?c++
- 如何为特定的模板数据类型设置条件
- 条件运算符:从'int '转换为"无符号字符",可能会丢失数据