2013-02-04 175 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雖然有點相關,但我認爲這是一個單獨的問題。如果你把它作爲一個單獨的問題發佈,我會很樂意盡你所能幫助你。 :) –