0

我将一个数据包作为客户端发送到服务器,我希望服务器将该数据包转发给所有客户端,代码如下:

#include <iostream>
#include <SFML/Network.hpp>
using namespace std;
int main()
{
int fromID; // receive data from 'fromID'
int Message; // fromID's message

sf::SocketTCP Listener;
if (!Listener.Listen(4567))
    return 1;
// Create a selector for handling several sockets (the listener + the socket associated to each client)
sf::SelectorTCP Selector;

Selector.Add(Listener);

while (true)
{
    unsigned int NbSockets = Selector.Wait();
    for (unsigned int i = 0; i < NbSockets; ++i)
    {
        // Get the current socket
        sf::SocketTCP Socket = Selector.GetSocketReady(i);

        if (Socket == Listener)
        {
        // If the listening socket is ready, it means that we can accept a new connection
            sf::IPAddress Address;
            sf::SocketTCP Client;
            Listener.Accept(Client, &Address);
            cout << "Client connected ! (" << Address << ")" << endl;

            // Add it to the selector
            Selector.Add(Client);
        }
        else
        {
            // Else, it is a client socket so we can read the data he sent
            sf::Packet Packet;
            if (Socket.Receive(Packet) == sf::Socket::Done)
            {

               // Extract the message and display it
                Packet >> Message;
                Packet >> fromID;
                cout << Message << " From: " << fromID << endl;

                //send the message to all clients
                for(unsigned int j = 0; j < NbSockets; ++j)
                {
                    sf::SocketTCP Socket2 = Selector.GetSocketReady(j);

                    sf::Packet SendPacket;
                    SendPacket << Message;
                    if(Socket2.Send(SendPacket) != sf::Socket::Done)
                        cout << "Error sending message to all clients" << endl;
                }
            }
            else
            {
              // Error : we'd better remove the socket from the selector
                Selector.Remove(Socket);
            }
        }
    }
}
return 0;

}

客户端代码:在 Player 类中我有这个功能:

void Player::ReceiveData()
{
 int mess;
 sf::Packet Packet;
 if(Client.Receive(Packet) == sf::Socket::Done)
 {
    Client.Receive(Packet);
    Packet >> mess;
    cout << mess << endl;
 }
}

主.cpp:

Player player;
player.Initialize();
player.LoadContent();
player.Connect();
..
..
//GAME LOOP
while(running==true)
{
   sf::Event Event;
   while(..) // EVENT LOOP
   {
   ...
   }
   player.Update(Window);
   player.ReceiveData();
   player.Draw(Window);
}

当我运行此客户端代码时,程序没有响应,冻结。问题在于 ReceiveDate() 函数。

4

1 回答 1

0

所有的套接字,即使是由 SFML 创建的,默认情况下都是阻塞的。这意味着当您尝试接收时,没有任何东西可以接收,调用将被阻塞,使您的应用程序看起来“冻结”。

您可以使用该函数切换 SFML 套接字的阻塞状态sf::SocketTCP::SetBlocking


发送给所有客户端失败的问题是因为你GetSocketReady用来让客户端发送到。该函数只为准备好的客户端返回一个套接字(即先前调用Wait将套接字标记为具有输入)。

您需要重构服务器以以另一种方式跟踪连接的客户端。常见的方法是每次在外循环中重置和重新创建选择器,并有一个单独的连接客户端集合(例如 a std::vector)。

于 2013-02-04T13:45:23.967 回答