Bonjour,
Je travaille actuellement sur un projet en C++ (langage dans lequel je suis loin d'être un expert) qui comporte un chat utilisant des sockets TCP.
Je fais face depuis quelques jours à un bug dont je ne peux déterminer la source (problème de conception ? bug SFML ?).
Je n'ai pas trouvé de bug à ce sujet concernant sfml-network sur le github.
Pour faire simple, j'utilise des structures qui représentent les données que j'envoie. J'ai implémenté les surcharges d'opérateurs adéquates pour l'insertion et l'extraction dans les sf::Packet.
A la connexion le client envoie ses identifiants, sous forme de 2 std::string (username et password). Sauf que,
si l'une des chaînes dépasse 16 caractères, le serveur plante
après avoir reçu et extrait les données correctement.
Le plus bizarre, c'est que
le bug apparait avec la SFML 2.1, mais pas avec la 2.0.J'ai réduit tout mon projet à un bout de code de ~180 lignes. (Je peux pas faire plus minimal que ça je pense). Comporte les côtés client & serveur.
Vous remarquerez que les surcharges des 2 opérateurs diffèrent. En effet, à l'envoi j'insère un identifiant qui permettra au serveur de savoir que c'est un "AuthPacket" et pas autre chose (un message dans le chat, un message privé, etc..).
Pour l'extraction, cet identifiant n'apparaît pas puisque le serveur l'extrait du sf::Packet juste avant.
Donc le serveur plante après le if(){} "
reading auth datas"
#include <iostream>
#include <sstream>
#include <vector>
#include <SFML/Network.hpp>
#define NET_PORT 11111
#define PACKET_AUTH 5
#define CLIENT_USERNAME "username"
#define CLIENT_SHA1PWD "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8"
// ----------------
// -- PROTOTYPES --
// ----------------
void Client();
void Server();
// -------------
// -- STRUCTS --
// -------------
struct AuthPacket
{
AuthPacket(std::string user = "", std::string sha1password = "")
: user(user), sha1password(sha1password)
{}
std::string user, sha1password;
};
// ----------------------------------------------
// -- SURCHARGES OPERATEUR LIEES AU sf::PACKET --
// ----------------------------------------------
// Serveur: Réception
sf::Packet& operator >> (sf::Packet& packet, AuthPacket& authPacket)
{
return packet >> authPacket.user >> authPacket.sha1password;
}
// Client: Envoi
sf::Packet& operator << (sf::Packet& packet, const AuthPacket authPacket)
{
return packet << (sf::Uint32) PACKET_AUTH << authPacket.user << authPacket.sha1password;
}
// ----------
// -- MAIN --
// ----------
int main(int argc, char** argv)
{
std::cout << "'c' to start a client / 's' to start a server: ";
std::string input;
std::cin >> input;
if(input == "s")
Server();
else if(input == "c")
Client();
while(1){}
exit(EXIT_SUCCESS);
}
// -------------
// -- METHODS --
// -------------
void Server() {
// clients
std::vector<std::shared_ptr<sf::TcpSocket>> clients;
// sfml network stuff
sf::TcpListener listener;
sf::SocketSelector selector;
sf::Socket::Status status = listener.listen(NET_PORT);
if(status != sf::Socket::Status::Done) {
exit(EXIT_FAILURE);
}
selector.add(listener);
// main loop
while(true)
{
if(selector.wait(sf::Time(sf::microseconds(50))))
{
// check server socket
if(selector.isReady(listener))
{
std::shared_ptr<sf::TcpSocket> client = std::make_shared<sf::TcpSocket>();
if(listener.accept(*client) == sf::Socket::Done)
{
std::cout << "New client connected" << std::endl;
selector.add(*client);
clients.push_back(client);
}
}
// check clients sockets
for(unsigned int i = 0; i < clients.size(); i++)
{
std::shared_ptr<sf::TcpSocket> client = clients[i];
sf::Packet packet;
// client message
if (selector.isReady(*client))
{
sf::Socket::Status status = client->receive(packet);
// packet status : OK
if(status == sf::Socket::Status::Done)
{
std::cout << "Received packet" << std::endl;
// packet code ?
sf::Uint32 packetCode;
if(packet >> packetCode) {
std::cout << "< Packet code: "<< packetCode << std::endl;
// packet code == AUTH
if(packetCode == (sf::Uint32) PACKET_AUTH)
{
// reading auth datas
AuthPacket authPacket;
if(packet >> authPacket)
{
std::cout << "< Packet content: " << authPacket.user << " / " << authPacket.sha1password << std::endl;
}
}
}
} // -- eof if(status == sf::Socket::Status::Done)
else {
selector.remove(*client);
}
} // -- eof if (selector.isReady(*client))
} // -- eof clients loop
} // -- eof if(selector.wait(sf::Time(sf::microseconds(50))))
} // -- eof main loop
}
void Client() {
sf::Socket::Status status = sf::Socket::Error;
sf::TcpSocket socket;
// connection attempt
if (status == sf::Socket::Disconnected || status == sf::Socket::Error)
{
socket.disconnect();
socket.setBlocking(false);
unsigned int max_retry = 50;
unsigned int attempt = 0;
while(true) {
status = socket.connect("127.0.0.1", NET_PORT);
if(status == sf::Socket::Status::Done)
break;
sf::sleep(sf::seconds(1));
}
}
// connection OK
if(status == sf::Socket::Status::Done)
{
// sending auth packet
AuthPacket authPacket(CLIENT_USERNAME, CLIENT_SHA1PWD);
sf::Packet packet;
std::cout << "> Packet content: "<< authPacket.user << " / " << authPacket.sha1password << std::endl;
packet << authPacket;
std::cout << "- Sent packet with status: " << socket.send(packet) << std::endl;
socket.disconnect();
}
}
Merci aux devs courageux qui oseront s'attaquer à mon problème!