-
I haven't tested client -> server -> client yet, just client -> server for now.
Unfortunately, I'm only able to send one message per connection.
Client
int main()
{
sf::SocketTCP Client;
// Create the main rendering window
sf::RenderWindow App(sf::VideoMode(480, 320, 32), "Window");
const sf::Input& Input = App.GetInput();
cout << "Type LEFT to connect, RIGHT to send a message, UP to disconnect" << endl;
// Start game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.GetEvent(Event))
{
if(Input.IsKeyDown(sf::Key::Left)){
if (Client.Connect(4567, "127.0.0.1") != sf::Socket::Done)
{
// Error...
cout << "error" << endl;
}
else cout << "connected" << endl;
}
else if(Input.IsKeyDown(sf::Key::Right)){
cout << "right pressed" << endl;
char Buffer[] = "Hi guys !";
if (Client.Send(Buffer, sizeof(Buffer)) != sf::Socket::Done)
{
// Error...
cout << "error sending message" << endl;
}
}
else if(Input.IsKeyDown(sf::Key::Up)){
Client.Close();
cout << "disconnected" << endl;
}
// Close window : exit
if (Event.Type == sf::Event::Closed)
App.Close();
}
// Clear the screen (fill it with black color)
App.Clear(sf::Color(255, 255, 255));
// Display window contents on screen
App.Display();
}
return EXIT_SUCCESS;
}
Left button connects, right button sends a message: "Hi guys !", up button disconnects/closes the socket.
Now on my server...
Server
void ThreadFunction(void* UserData)
{
Server *server = (Server*)UserData;
char Buffer[128];
std::size_t Received;
while(true){
sf::IPAddress ClientAddress;
if (server->Listener.Accept(server->Client, &ClientAddress) != sf::Socket::Done)
{
// Error...
//cout << "Error listening..." << endl;
}
else{
cout << "Got a connection!" << endl;
}
if (server->Client.Receive(Buffer, sizeof(Buffer), Received) != sf::Socket::Done)
{
// Error...
continue;
}
else{
cout << "Message: " << Buffer << endl;
}
}
}
I can connect, and send a message, but just one message.
If I disconnect and connect again, I can send a message, but only one.
Not sure what's going on. I should be able to send multiple ones.
-
Your server does this:
infinite loop
{
wait for a new client
wait a message from this client
}
So after it has received a message, it waits for a new client.
And in your client code, you shouldn't mix events and inputs. If you want to react to single key press events, you should use the information contained in your sf::Event structure inside your event loop.
-
Not really sure how to fix the problem for the server.
Don't we need to continuously listen for new connections using a loop?
I'm a bit clueless on where in my program these codes need to be.
-
Don't we need to continuously listen for new connections using a loop?
Yes, but while the socket waits for new connections, the entire thread is blocked and cannot do anything else.
The solutions that you can use are:
- switch to non-blocking sockets
- use more threads to avoid actions blocking each other
- use a selector
See the tutorials and documentation for more details :)
-
Well I tried non-blocking sockets:
Listener.SetBlocking(false);
Client.SetBlocking(false);
Can still send one message per connection.
I've also tried using different threads:
void ThreadNet(void* UserData){
Server *server = (Server*)UserData;
char Buffer[128];
std::size_t Received;
while(true){
if (server->Client.Receive(Buffer, sizeof(Buffer), Received) != sf::Socket::Done)
{
// Error...
continue;
}
else{
cout << "Message: " << Buffer << endl;
}
}
}
void ThreadFunction(void* UserData)
{
Server *server = (Server*)UserData;
while(true){
sf::IPAddress ClientAddress;
if (server->Listener.Accept(server->Client, &ClientAddress) != sf::Socket::Done)
{
// Error...
//cout << "Error listening..." << endl;
}
else{
cout << "Got a connection!" << endl;
}
}
}
Still just one message per connection...
-
I've also tried using a selector.
Only this time, I can't receive any messages, besides the one when they connect to my server:
void ThreadFunction(void* UserData)
{
Server *server = (Server*)UserData;
char Buffer[128];
std::size_t Received;
while(true){
unsigned int NbSockets = server->Selector.Wait();
for(unsigned int i = 0; i < NbSockets; ++i){
sf::SocketTCP Socket = server->Selector.GetSocketReady(i);
//Look for new connections
if(Socket == server->Listener){
sf::IPAddress Address;
sf::SocketTCP Client;
server->Listener.Accept(Client, &Address);
cout << "Got a client" << endl;
server->Selector.Add(Client);
}
//Read data from clients
else{
sf::Packet Packet;
if(Socket.Receive(Packet) == sf::Socket::Done){
//Get the message
std::string Message;
//Put whatever is in the Packet to the string
Packet >> Message;
cout << "Message: " << Message << endl;
}
else{
server->Selector.Remove(Socket);
}
}
}
}
}
What I'm using to send a message:
char Buffer[] = "Hi guys !";
if (Client.Send(Buffer, sizeof(Buffer)) != sf::Socket::Done)
{
// Error...
cout << "error sending message" << endl;
}
-
But... what is your main thread doing while the network thread is running?
-
It's asking for commands.
Here's my entire main.cpp for my server:
/************************************************************
SERVER
************************************************************/
#include <iostream>
#include <string>
#include "Server.h"
#include <SFML/System.hpp>
using namespace std;
int command(Server *s, std::string line);
void ThreadFunction(void* UserData);
bool running;
void ThreadFunction(void* UserData)
{
Server *server = (Server*)UserData;
char Buffer[128];
std::size_t Received;
while(true){
unsigned int NbSockets = server->selector.Wait();
for(unsigned int i = 0; i < NbSockets; ++i){
sf::SocketTCP Socket = server->selector.GetSocketReady(i);
//Look for new connections
if(Socket == server->Listener){
sf::IPAddress Address;
sf::SocketTCP Client;
server->Listener.Accept(Client, &Address);
cout << "Got a client" << endl;
server->selector.Add(Client);
}
//Read data from clients
else{
sf::Packet Packet;
if(Socket.Receive(Packet) == sf::Socket::Done){
//Get the message
std::string Message;
//Put whatever is in the Packet to the string
Packet >> Message;
cout << "Message: " << Message << endl;
}
else{
server->selector.Remove(Socket);
}
}
}
}
}
//Entry
int main(){
Server server;
sf::Thread thread(&ThreadFunction, &server);
running = true;
thread.Launch();
string line;
cout << "==========================" << endl;
cout << "Welcome to the NetServer." << endl;
cout << "==========================" << endl;
cout << endl;
cout << "====================================================" << endl;
cout << "Enter a command. For a list of commands type \"help\"." << endl;
cout << "====================================================" << endl;
while (running){
int ret;
if(std::getline(cin, line)){
if(ret = command(&server, line) != 0)
return ret;
}
}
}
//Loop
int command(Server *server, std::string line){
cout << endl;
//Process line
if(line == "help"){
cout << "<LIST OF COMMANDS:>" << endl;
cout << "help - Displays help" << endl
<< "start - Starts the server" << endl
<< "stop - Stops the server" << endl;
}
else if(line == "start"){
server->start();
}
else if(line == "stop"){
server->stop();
}
else{
cout << endl;
cout << "=========================" << endl;
cout << "Invalid. Enter a command." << endl;
cout << "=========================" << endl;
return 0;
}
cout << endl;
cout << "================" << endl;
cout << "Enter a command." << endl;
cout << "================" << endl;
return 0;
}
-
Can you please use the code=cpp tag so that I can stop editing all your messages?
-
Sorry, didn't know I could do that.
Do you know what may be the problem?
-
Can you show the code of the Server class?
-
#include "Server.h"
#include <iostream>
using namespace std;
Server::Server(){
started = false;
Listener.SetBlocking(false);
}
void Server::start(){
if(!started){
//Check TCP Socket
cout << "Attempting to listen on TCP port: 4567...." << endl;
if (!Listener.Listen(4567))
{
// Error...
cout << "Could not listen on TCP port: 4567." << endl;
return;
}
cout << "Listening on port 4567" << endl;
started = true;
cout << "Server started." << endl;
selector.Add(Listener);
}
else{
cout << "Server is all ready running." << endl;
}
}
void Server::stop(){
cout << "Stopping server..." << endl;
started = false;
unsigned int NbSockets = selector.Wait();
for(unsigned int i = 0; i < NbSockets; ++i){
selector.GetSocketReady(i).Close();
}
}
-
Don't mix selectors and non-blocking sockets, it doesn't make sense. And don't forget to check the result of the Accept function.
-
Well I've redone my entire server and client.
Unfortunately I'm still getting the same result as before.
I can only get one message at a time per client/connection....
CLIENT:
/************************************************************
CLIENT
************************************************************/
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <SFML/Network.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////
/// Entry point of application
///
/// \return Application exit code
///
////////////////////////////////////////////////////////////
int main()
{
//Server we are connecting to (via TCP)
bool closedConnection = false; //if we closed the socket yet or not
sf::SocketTCP Server;
Server.SetBlocking(false); //It honestly makes no difference whether it's true/false, same problem still
char Message1[] = "Hello!";
char Message2[] = "Again!";
cout << "test" << endl;
if (Server.Connect(4567, "127.0.0.1") != sf::Socket::Done)
{
// Error...
cout << "Unable to connect to server" << endl;
}
else{
cout << "Connected to server" << endl;
}
if (Server.Send(Message1, sizeof(Message1)) != sf::Socket::Done)
{
// Error...
}
else{
cout << "Sent message to server" << endl;
}
if (Server.Send(Message2, sizeof(Message2)) != sf::Socket::Done)
{
// Error...
}
else{
cout << "Sent message to server" << endl;
}
// Create the main rendering window
sf::RenderWindow App(sf::VideoMode(480, 320, 32), "Window");
const sf::Input& Input = App.GetInput();
// Start game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.GetEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed){
//Player decided to close the program
//Check if we've closed the socket yet
//If we haven't, close it
if(!closedConnection){
Server.Close();
closedConnection = true;
}
App.Close();
}
}
// Clear the screen (fill it with black color)
App.Clear(sf::Color(255, 255, 255));
// Display window contents on screen
App.Display();
}
//We come to the end of the program
//Check if we've closed the socket yet
//If we haven't, close it
if(!closedConnection){
Server.Close();
closedConnection = true;
}
return EXIT_SUCCESS;
}
SERVER:
/************************************************************
SERVER
************************************************************/
#include <iostream>
#include <SFML/Network.hpp>
#include <SFML/System.hpp>
using namespace std;
//Entry
int main(){
sf::SocketTCP Client;
sf::IPAddress ClientAddress;
sf::SocketTCP Listener;
Client.SetBlocking(false); //It honestly makes no difference whether it's true/false, same problem still
Listener.SetBlocking(false); //It honestly makes no difference whether it's true/false, same problem still
//Buffer to receive messages
char Buffer[128];
//How many messages we've received
std::size_t Received;
bool running = true;
if (!Listener.Listen(4567))
{
// Error...
cout << "Unable to listen on TCP port: 4567" << endl;
}
else{
cout << "Listening on TCP port: 4567" << endl;
}
while(running){
//Waits until a incoming connection arrives
if (Listener.Accept(Client, &ClientAddress) != sf::Socket::Done)
{
// Error...
//cout << "Unable to accept any incoming connections" << endl;
}
else{
cout << "Accepted a Client!" << endl;
}
if (Client.Receive(Buffer, sizeof(Buffer), Received) != sf::Socket::Done)
{
// Error...
//cout << "Unable to receive any messages from client." << endl;
}
else{
cout << "Message: " << Buffer << endl;
}
}
}
-
I'd like to test your code, but it uses SFML 1.6. Don't you want to upgrade to SFML 2 (which is a much better version anyway)?
-
There doesn't appear to be any tutorials on version 2.0 for networking (unless I saw wrong).
I've got a roster of people all ready setup for 1.6 and we'd rather not switch as we've been working
hard with 1.6. Anyways....
To be honest I'd rather want to know what's wrong with my code now.
I've gone over the tutorial on the TCP section and I'm absolutely dumbfounded why I can only
get just one message per connection.....
Could you possibly test it to determine what's wrong? I've been stuck on this for a while.
-
I would recommend using threads, as non-blocking sockets are a bit more complicated than they appear.
-
Could you possibly test it to determine what's wrong? I've been stuck on this for a while.
My free time is really reduced to minimum, so I'm a little lazy and never test 1.6 code. Also because I have stopped maintaining SFML 1.6 3 years ago and a lot of bugs have been fixed in SFML 2. Sorry.
Although the tutorials are not written yet, networking hasn't changed much and you should be able to convert your code easily with the 1.6 tutorials and the 2.0 API documentation (which is much more detailed and has useful examples).
I would recommend using threads, as non-blocking sockets are a bit more complicated than they appear.
Not really. At least not for this use case.
-
Well depending on the situation, the packet-end byte in a non-blocking socket system isn't recognized by the client or server so certain protocols will appear to cluster packets together.
-
another thing you could do is multithreading your server so it can have more than one client at a time. It's good for when you want any number of clients on a given server but it helps if the code is as reuseable as you can get it. As soon as I get done fighting with an Object/Memory manager I'll see what dig up on issues like this.
-
another thing you could do is multithreading your server so it can have more than one client at a time. It's good for when you want any number of clients on a given server but it helps if the code is as reuseable as you can get it. As soon as I get done fighting with an Object/Memory manager I'll see what dig up on issues like this.
Multithreading with sockets is generally a bad idea, usually if you do it wrong. A process can only have ~2000 threads (a lot of the time much less, depending on the system and whatnot), so having a big server can screw things up. Plus processor affinity can play an issue if a client is sending malicious content; it can potentially slow down the main thread, or another crucial thread.
If you want to have something similar to multithreading, it's best practice to use non-blocking sockets.