Я отправляю пакет как клиент на сервер и хочу, чтобы сервер отправлял этот пакет всем клиентам, вот код:
#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 ().
Все сокеты, даже созданные SFML, по умолчанию блокируются. Это означает, что когда вы пытаетесь получить, когда нечего получать, вызов блокируется, в результате чего ваше приложение кажется «замороженным».
Вы можете переключить статус блокировки сокета SFML с помощью sf::SocketTCP::SetBlocking
функция.
Проблема с отправкой всем клиентам не удалась, потому что вы используете GetSocketReady
чтобы клиенты отправляли. Эта функция возвращает сокет только для клиентов, которые готовы (т.е. предыдущий вызов Wait
пометил сокет как имеющий вход).
Вам необходимо провести рефакторинг сервера, чтобы отслеживать подключенных клиентов другим способом. Обычным способом является сброс и повторное создание селектора каждый раз во внешнем цикле и получение отдельной коллекции подключенных клиентов (например, a std::vector
).
Других решений пока нет …