【问题标题】:SFML TCP packet receiveSFML TCP 数据包接收
【发布时间】:2013-02-04 12:42:34
【问题描述】:

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

#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() 函数。

【问题讨论】:

  • 你确定不是服务器的问题吗?在调试器中运行并在接收消息的位置设置断点,然后逐行执行代码以查看会发生什么。
  • 服务器在其他电脑上运行,只有客户端死机。所以..这是一个游戏,客户端不会冻结,直到我按下某个按钮,但只出现白屏,因为 player.ReceiveData() 正在运行,直到我收到一个数据包或什么?我不明白..
  • 记住套接字默认是阻塞的。这意味着Receive 调用将阻塞,直到有东西要接收。因此,当涉及到Receive 调用时,您的程序将“冻结”。
  • 所以我需要创建线程?
  • 不,请参阅sf::SocketTCP::SetBlocking 函数。

标签: c++ tcp sfml packet


【解决方案1】:

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

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


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

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

【讨论】:

  • @user1949520 虽然有些相关,但我认为这需要一个单独的问题。如果您将其作为单独的问题发布,我很乐意尽我所能帮助您。 :)
猜你喜欢
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 2016-12-16
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多