SFML TCP数据包接收 [英] SFML TCP packet receive
问题描述
我将一个数据包作为客户端发送到服务器,我想要服务器将该数据包发送到所有客户端,这里是代码:
#include< iostream>
#include< SFML / Network.hpp>
using namespace std;
int main()
{
int fromID; //从'fromID'接收数据
int消息; // fromID的消息
sf :: SocketTCP Listener;
if(!Listener.Listen(4567))
return 1;
//创建一个选择器来处理多个套接字(侦听器+与每个客户端关联的套接字)
sf :: SelectorTCP Selector;
Selector.Add(Listener);
while(true)
{
unsigned int NbSockets = Selector.Wait();
for(unsigned int i = 0; i {
//获取当前套接字
sf :: SocketTCP Socket = Selector.GetSocketReady一世);
if(Socket == Listener)
{
//如果侦听套接字准备就绪,这意味着我们可以接受一个新的连接
sf :: IPAddress地址;
sf :: SocketTCP Client;
Listener.Accept(Client,& Address);
cout<< Client connected!(<< Address<<)< endl;
//将其添加到选择器
Selector.Add(Client);
}
else
{
// Else,它是一个客户端套接字,所以我们可以读取他发送的数据
sf :: Packet Packet;
if(Socket.Receive(Packet)== sf :: Socket :: Done)
{
//提取消息并显示它
Packet> >信息;
Packet>> fromID;
cout<<消息<< From:< fromID<< endl;
//将消息发送到所有客户端
for(unsigned int j = 0; j {
sf :: SocketTCP Socket2 = Selector.GetSocketReady(j);
sf :: Packet SendPacket;
SendPacket<<信息;
if(Socket2.Send(SendPacket)!= sf :: Socket :: Done)
cout< 向所有客户端发送消息时出错< endl;
}
}
else
{
//错误:我们最好从选择器中删除套接字
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>> ;
cout<<坏< endl;
}
}
main.cpp:
玩家;
player.Initialize();
player.LoadContent();
player.Connect();
..
..
//游戏LOOP
while(running == true)
{
sf :: Event Event;
while(..)//事件循环
{
...
}
player.Update(Window);
player.ReceiveData();
player.Draw(Window);
}
当我运行这个客户端代码时,程序没有响应,冻结。所有套接字,即使是由SFML创建的套接字,都是由以下方法创建的:
默认阻塞。这意味着当您尝试接收没有什么可接受时,调用会阻塞,使您的应用程序似乎冻结。
您可以切换阻止状态一个包含 sf :: SocketTCP :: Set blocking
函数。
发送到所有客户端失败的问题是因为您可以使用 GetSocketReady
来获取客户端发送到。该函数只为客户端 ready 返回一个套接字(即,之前调用 Wait
将套接字标记为有输入)。
您需要重构服务器,以另一种方式跟踪连接的客户端。常见的方法是每次在外层循环中重置和重新创建选择器,并且具有连接的客户端的单独集合(例如 std :: vector
)。 p>
I send a packet as client to server and I want to the server sends that packet forward to all client, here is the code:
#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;
}
Client code: in Player class I have this function :
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);
}
When I run this client code, the program not responding, freezes. The problem is with that ReceiveDate() function.
All sockets, even the one created by SFML, are by default blocking. This means that when you try to receive when there is nothing to receive, the call will block, making your application seem "freezed".
You can toggle the blocking status of a SFML socket with the sf::SocketTCP::SetBlocking
function.
The problem with sending to all clients failing is because you use GetSocketReady
to get the clients to send to. That function only returns a socket for clients that are ready (i.e. the previous call to Wait
marked the socket as having input).
You need to refactor the server to keep track of the connected clients in another way. The common way is to reset and recreate the selector every time in the outer loop, and have a separate collection of the connected clients (e.g. a std::vector
).
这篇关于SFML TCP数据包接收的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!