2013-02-04 64 views
0

我发送一个数据包的客户端服务器,我想给服务器发送数据包转发到所有客户端,这里是代码:SFML TCP数据包接收

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

+0

你确定这不是服务器问题吗?在调试器中运行,并在接收消息的位置设置断点,然后逐行浏览代码以查看发生的情况。 –

+0

服务器在其他电脑上运行,只有客户端冻结。所以......这是一个游戏,客户端不会冻结,直到我按下某个按钮,但只出现白色屏幕,becoz player.ReceiveData()正在运行,直到我收到一个包或什么?我不明白.. – cylon

+0

请记住,默认情况下,套接字是_blocking_。这意味着'receive'调用将被阻塞,直到有东西被接收。所以你的程序在“Receive”调用时会“冻结”。 –

回答

0

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

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


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

您需要重构服务器以通过其他方式跟踪连接的客户端。常用的方法是每次在外部循环中重置和重新创建选择器,并且具有单独的连接客户端集合(例如std::vector)。

+0

你能帮我一些代码吗? :) – cylon

+0

@ user1949520虽然有点相关,但我认为这是一个单独的问题。如果你把它作为一个单独的问题发布,我会很乐意尽你所能帮助你。 :) –