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;
 }
}

main.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 に答える