SFML Detect multiple connections to server and count them
I'm creating a very simple client/server application.
I want my server to detect how many clients have connected and if there are more than 2, just print a message.
The code for the server I have so far is very minimal:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
while (clients.size() < 2)
{
printf("Waiting for second connection...n");
}
The problem I have is that it detects the first connection with no problem, but it doesn't detect the second one, even though my second client is connected. For the client connection I'm just using the very simple code explained in the SFML documentation.
I'm very confused as clients.size() always returns 1.
c++ sockets networking sfml
add a comment |
I'm creating a very simple client/server application.
I want my server to detect how many clients have connected and if there are more than 2, just print a message.
The code for the server I have so far is very minimal:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
while (clients.size() < 2)
{
printf("Waiting for second connection...n");
}
The problem I have is that it detects the first connection with no problem, but it doesn't detect the second one, even though my second client is connected. For the client connection I'm just using the very simple code explained in the SFML documentation.
I'm very confused as clients.size() always returns 1.
c++ sockets networking sfml
add a comment |
I'm creating a very simple client/server application.
I want my server to detect how many clients have connected and if there are more than 2, just print a message.
The code for the server I have so far is very minimal:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
while (clients.size() < 2)
{
printf("Waiting for second connection...n");
}
The problem I have is that it detects the first connection with no problem, but it doesn't detect the second one, even though my second client is connected. For the client connection I'm just using the very simple code explained in the SFML documentation.
I'm very confused as clients.size() always returns 1.
c++ sockets networking sfml
I'm creating a very simple client/server application.
I want my server to detect how many clients have connected and if there are more than 2, just print a message.
The code for the server I have so far is very minimal:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
while (clients.size() < 2)
{
printf("Waiting for second connection...n");
}
The problem I have is that it detects the first connection with no problem, but it doesn't detect the second one, even though my second client is connected. For the client connection I'm just using the very simple code explained in the SFML documentation.
I'm very confused as clients.size() always returns 1.
c++ sockets networking sfml
c++ sockets networking sfml
asked Nov 23 '18 at 14:04
Koosshh56Koosshh56
1578
1578
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Because you don't accept a second connection...
Changing code order a little:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
while (clients.size() < 2)
{
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
// OK, that one would be printed twice!!!
printf("Waiting for second connection...n");
}
This won't be the final loop, though, it is just intended for demonstration.
Be aware that you don't delete the clients created anywhere (-> memory leak!). You might consider usage of smart pointers instead of raw pointers.
OK, so now: you want to accept arbitrary number of clients, and as soon as number you have more than two clients, run some application.
At very first, you need to continue accepting new clients on the loop (I changed the logging messages a little...:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
return; // no need to go on on error!
}
printf("start waiting for clients...n");
for(;;) // endless loop...
{
sf::TcpSocket* socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
// TODO: consider some appropriate error handling
// minimally:
delete socket; // otherwise, you produce memory leaks!
}
clients.push_back(socket);
printf
(
"new client accepted; number of clients now: %llun"
"continue waiting...n",
clients.size()
);
// llu: most likely on 64-bit machine, on 32 bit either lu or u,
// depending on type of size_t; you get around having to decide
// if using C++ streams instead...
}
Problem now is: You additionally need to handle the connections appropriately! Have a look at this SFML tutorial, especially the section Blocking on a group of sockets. The selector described there is exactly what you need. Most important:
A selector can monitor all types of sockets: sf::TcpSocket, sf::UdpSocket, and sf::TcpListener.
So you can add all of your sockets and the listener to. You still have to maintain your instances yourself, though:
A selector is not a socket container. It only references (points to) the sockets that you add, it doesn't store them. There is no way to retrieve or count the sockets that you put inside. Instead, [...].
Well, you covered the 'instead' part already with your vector. Normally I'd recommend storing the objects in the vector directly; however, you cannot, as you need references to in the selector. So you need to store pointers in the vector – or you can use a std::list
instead, which won't invalidate references or pointers to stored data on insertion or deletion of objects (apart from pointers to the removed object itself, of course).
If you want to stay with the vector, you might consider using smart pointers, though, so that you don't have to care for memory management (e. g. std::vector<std::unique_ptr<sf::TcpSocket>> clients
).
I personally would prefer the std::list
:
std::list<sf::TcpSocket> clients; // notice: no pointers...
sf::TcpListener listener;
sf::SocketSelector selector;
selector.add(listener); // you want to listen as well...
for(;;)
{
// wait on selector as described in tutorial, I'd recommend only
// waiting for one second: you might want to handle the application
// exiting at some point of time!
}
If waiting was successful, you'd now first check the server socket, then the clients):
if(listener.isReady())
{
// OK, we now know that a client is waiting, so next steps won't block:
clients.emplace_back(); // new client
if(listener.accept(clients.back()) != sf::Socket::Done)
{
// OK, something went wrong, current client us valueless...
clients.pop_back();
// adding and then removing? well, normally, this case here
// should not occur anyway, so we optimized for the far more
// common case.
}
else
{
// want to listen on as well
selector.add(clients.back());
}
}
for(auto& c : clients)
{
if(c.isReady())
{
// handle communication
}
}
Handling communinication is up to you... I wouldn't just communicate if at least two clients are connected. If you leave the messages from one single client unhandled, you might end up in needing to handle quite a bunch of outdated messages as soon as another client arrives, so I'd rather handle anything incoming immediately even with one single client. If it appears more appropriate to you, you might still place a if(clients.size() >= 2)
around the (range based) for loop.
If a client disconnects, don't forget to remove it from the selector! Having done so, you can safely remove it from the clients list as well.
Finally: the endless loop!
You might want to replace this via some conditional loop, checking if the server should still be running at all or not. You'd then yet need some mechanism to set this condition to false. There are different options for, e. g. some separate thread checking some specific input, signals (especially on POSIX systems), ...
I've just tried your first solution and it's not really working. When I connect the first client, client.size() is equal to 2, even if I haven't connected my second client yet. Also, I don' really want exactly 2 clients, but at least 2...if that makes sense. It will be a matchmaking system...
– Koosshh56
Nov 23 '18 at 14:49
Also, I tried to increase the while condition thresholdclients.size() < 2
to 10, and it counts one connection as 3...so the clients.size() increases by 3 every time I connect a client
– Koosshh56
Nov 23 '18 at 14:55
any help with this? I'm still stuck. Thanks
– Koosshh56
Nov 26 '18 at 9:19
@Koosshh56 Without seing your changed code, a bit difficult to guess the issues... I modified this answer, though, so it (hopefully) covers your needs better.
– Aconcagua
Nov 26 '18 at 11:18
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53448141%2fsfml-detect-multiple-connections-to-server-and-count-them%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Because you don't accept a second connection...
Changing code order a little:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
while (clients.size() < 2)
{
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
// OK, that one would be printed twice!!!
printf("Waiting for second connection...n");
}
This won't be the final loop, though, it is just intended for demonstration.
Be aware that you don't delete the clients created anywhere (-> memory leak!). You might consider usage of smart pointers instead of raw pointers.
OK, so now: you want to accept arbitrary number of clients, and as soon as number you have more than two clients, run some application.
At very first, you need to continue accepting new clients on the loop (I changed the logging messages a little...:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
return; // no need to go on on error!
}
printf("start waiting for clients...n");
for(;;) // endless loop...
{
sf::TcpSocket* socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
// TODO: consider some appropriate error handling
// minimally:
delete socket; // otherwise, you produce memory leaks!
}
clients.push_back(socket);
printf
(
"new client accepted; number of clients now: %llun"
"continue waiting...n",
clients.size()
);
// llu: most likely on 64-bit machine, on 32 bit either lu or u,
// depending on type of size_t; you get around having to decide
// if using C++ streams instead...
}
Problem now is: You additionally need to handle the connections appropriately! Have a look at this SFML tutorial, especially the section Blocking on a group of sockets. The selector described there is exactly what you need. Most important:
A selector can monitor all types of sockets: sf::TcpSocket, sf::UdpSocket, and sf::TcpListener.
So you can add all of your sockets and the listener to. You still have to maintain your instances yourself, though:
A selector is not a socket container. It only references (points to) the sockets that you add, it doesn't store them. There is no way to retrieve or count the sockets that you put inside. Instead, [...].
Well, you covered the 'instead' part already with your vector. Normally I'd recommend storing the objects in the vector directly; however, you cannot, as you need references to in the selector. So you need to store pointers in the vector – or you can use a std::list
instead, which won't invalidate references or pointers to stored data on insertion or deletion of objects (apart from pointers to the removed object itself, of course).
If you want to stay with the vector, you might consider using smart pointers, though, so that you don't have to care for memory management (e. g. std::vector<std::unique_ptr<sf::TcpSocket>> clients
).
I personally would prefer the std::list
:
std::list<sf::TcpSocket> clients; // notice: no pointers...
sf::TcpListener listener;
sf::SocketSelector selector;
selector.add(listener); // you want to listen as well...
for(;;)
{
// wait on selector as described in tutorial, I'd recommend only
// waiting for one second: you might want to handle the application
// exiting at some point of time!
}
If waiting was successful, you'd now first check the server socket, then the clients):
if(listener.isReady())
{
// OK, we now know that a client is waiting, so next steps won't block:
clients.emplace_back(); // new client
if(listener.accept(clients.back()) != sf::Socket::Done)
{
// OK, something went wrong, current client us valueless...
clients.pop_back();
// adding and then removing? well, normally, this case here
// should not occur anyway, so we optimized for the far more
// common case.
}
else
{
// want to listen on as well
selector.add(clients.back());
}
}
for(auto& c : clients)
{
if(c.isReady())
{
// handle communication
}
}
Handling communinication is up to you... I wouldn't just communicate if at least two clients are connected. If you leave the messages from one single client unhandled, you might end up in needing to handle quite a bunch of outdated messages as soon as another client arrives, so I'd rather handle anything incoming immediately even with one single client. If it appears more appropriate to you, you might still place a if(clients.size() >= 2)
around the (range based) for loop.
If a client disconnects, don't forget to remove it from the selector! Having done so, you can safely remove it from the clients list as well.
Finally: the endless loop!
You might want to replace this via some conditional loop, checking if the server should still be running at all or not. You'd then yet need some mechanism to set this condition to false. There are different options for, e. g. some separate thread checking some specific input, signals (especially on POSIX systems), ...
I've just tried your first solution and it's not really working. When I connect the first client, client.size() is equal to 2, even if I haven't connected my second client yet. Also, I don' really want exactly 2 clients, but at least 2...if that makes sense. It will be a matchmaking system...
– Koosshh56
Nov 23 '18 at 14:49
Also, I tried to increase the while condition thresholdclients.size() < 2
to 10, and it counts one connection as 3...so the clients.size() increases by 3 every time I connect a client
– Koosshh56
Nov 23 '18 at 14:55
any help with this? I'm still stuck. Thanks
– Koosshh56
Nov 26 '18 at 9:19
@Koosshh56 Without seing your changed code, a bit difficult to guess the issues... I modified this answer, though, so it (hopefully) covers your needs better.
– Aconcagua
Nov 26 '18 at 11:18
add a comment |
Because you don't accept a second connection...
Changing code order a little:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
while (clients.size() < 2)
{
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
// OK, that one would be printed twice!!!
printf("Waiting for second connection...n");
}
This won't be the final loop, though, it is just intended for demonstration.
Be aware that you don't delete the clients created anywhere (-> memory leak!). You might consider usage of smart pointers instead of raw pointers.
OK, so now: you want to accept arbitrary number of clients, and as soon as number you have more than two clients, run some application.
At very first, you need to continue accepting new clients on the loop (I changed the logging messages a little...:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
return; // no need to go on on error!
}
printf("start waiting for clients...n");
for(;;) // endless loop...
{
sf::TcpSocket* socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
// TODO: consider some appropriate error handling
// minimally:
delete socket; // otherwise, you produce memory leaks!
}
clients.push_back(socket);
printf
(
"new client accepted; number of clients now: %llun"
"continue waiting...n",
clients.size()
);
// llu: most likely on 64-bit machine, on 32 bit either lu or u,
// depending on type of size_t; you get around having to decide
// if using C++ streams instead...
}
Problem now is: You additionally need to handle the connections appropriately! Have a look at this SFML tutorial, especially the section Blocking on a group of sockets. The selector described there is exactly what you need. Most important:
A selector can monitor all types of sockets: sf::TcpSocket, sf::UdpSocket, and sf::TcpListener.
So you can add all of your sockets and the listener to. You still have to maintain your instances yourself, though:
A selector is not a socket container. It only references (points to) the sockets that you add, it doesn't store them. There is no way to retrieve or count the sockets that you put inside. Instead, [...].
Well, you covered the 'instead' part already with your vector. Normally I'd recommend storing the objects in the vector directly; however, you cannot, as you need references to in the selector. So you need to store pointers in the vector – or you can use a std::list
instead, which won't invalidate references or pointers to stored data on insertion or deletion of objects (apart from pointers to the removed object itself, of course).
If you want to stay with the vector, you might consider using smart pointers, though, so that you don't have to care for memory management (e. g. std::vector<std::unique_ptr<sf::TcpSocket>> clients
).
I personally would prefer the std::list
:
std::list<sf::TcpSocket> clients; // notice: no pointers...
sf::TcpListener listener;
sf::SocketSelector selector;
selector.add(listener); // you want to listen as well...
for(;;)
{
// wait on selector as described in tutorial, I'd recommend only
// waiting for one second: you might want to handle the application
// exiting at some point of time!
}
If waiting was successful, you'd now first check the server socket, then the clients):
if(listener.isReady())
{
// OK, we now know that a client is waiting, so next steps won't block:
clients.emplace_back(); // new client
if(listener.accept(clients.back()) != sf::Socket::Done)
{
// OK, something went wrong, current client us valueless...
clients.pop_back();
// adding and then removing? well, normally, this case here
// should not occur anyway, so we optimized for the far more
// common case.
}
else
{
// want to listen on as well
selector.add(clients.back());
}
}
for(auto& c : clients)
{
if(c.isReady())
{
// handle communication
}
}
Handling communinication is up to you... I wouldn't just communicate if at least two clients are connected. If you leave the messages from one single client unhandled, you might end up in needing to handle quite a bunch of outdated messages as soon as another client arrives, so I'd rather handle anything incoming immediately even with one single client. If it appears more appropriate to you, you might still place a if(clients.size() >= 2)
around the (range based) for loop.
If a client disconnects, don't forget to remove it from the selector! Having done so, you can safely remove it from the clients list as well.
Finally: the endless loop!
You might want to replace this via some conditional loop, checking if the server should still be running at all or not. You'd then yet need some mechanism to set this condition to false. There are different options for, e. g. some separate thread checking some specific input, signals (especially on POSIX systems), ...
I've just tried your first solution and it's not really working. When I connect the first client, client.size() is equal to 2, even if I haven't connected my second client yet. Also, I don' really want exactly 2 clients, but at least 2...if that makes sense. It will be a matchmaking system...
– Koosshh56
Nov 23 '18 at 14:49
Also, I tried to increase the while condition thresholdclients.size() < 2
to 10, and it counts one connection as 3...so the clients.size() increases by 3 every time I connect a client
– Koosshh56
Nov 23 '18 at 14:55
any help with this? I'm still stuck. Thanks
– Koosshh56
Nov 26 '18 at 9:19
@Koosshh56 Without seing your changed code, a bit difficult to guess the issues... I modified this answer, though, so it (hopefully) covers your needs better.
– Aconcagua
Nov 26 '18 at 11:18
add a comment |
Because you don't accept a second connection...
Changing code order a little:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
while (clients.size() < 2)
{
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
// OK, that one would be printed twice!!!
printf("Waiting for second connection...n");
}
This won't be the final loop, though, it is just intended for demonstration.
Be aware that you don't delete the clients created anywhere (-> memory leak!). You might consider usage of smart pointers instead of raw pointers.
OK, so now: you want to accept arbitrary number of clients, and as soon as number you have more than two clients, run some application.
At very first, you need to continue accepting new clients on the loop (I changed the logging messages a little...:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
return; // no need to go on on error!
}
printf("start waiting for clients...n");
for(;;) // endless loop...
{
sf::TcpSocket* socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
// TODO: consider some appropriate error handling
// minimally:
delete socket; // otherwise, you produce memory leaks!
}
clients.push_back(socket);
printf
(
"new client accepted; number of clients now: %llun"
"continue waiting...n",
clients.size()
);
// llu: most likely on 64-bit machine, on 32 bit either lu or u,
// depending on type of size_t; you get around having to decide
// if using C++ streams instead...
}
Problem now is: You additionally need to handle the connections appropriately! Have a look at this SFML tutorial, especially the section Blocking on a group of sockets. The selector described there is exactly what you need. Most important:
A selector can monitor all types of sockets: sf::TcpSocket, sf::UdpSocket, and sf::TcpListener.
So you can add all of your sockets and the listener to. You still have to maintain your instances yourself, though:
A selector is not a socket container. It only references (points to) the sockets that you add, it doesn't store them. There is no way to retrieve or count the sockets that you put inside. Instead, [...].
Well, you covered the 'instead' part already with your vector. Normally I'd recommend storing the objects in the vector directly; however, you cannot, as you need references to in the selector. So you need to store pointers in the vector – or you can use a std::list
instead, which won't invalidate references or pointers to stored data on insertion or deletion of objects (apart from pointers to the removed object itself, of course).
If you want to stay with the vector, you might consider using smart pointers, though, so that you don't have to care for memory management (e. g. std::vector<std::unique_ptr<sf::TcpSocket>> clients
).
I personally would prefer the std::list
:
std::list<sf::TcpSocket> clients; // notice: no pointers...
sf::TcpListener listener;
sf::SocketSelector selector;
selector.add(listener); // you want to listen as well...
for(;;)
{
// wait on selector as described in tutorial, I'd recommend only
// waiting for one second: you might want to handle the application
// exiting at some point of time!
}
If waiting was successful, you'd now first check the server socket, then the clients):
if(listener.isReady())
{
// OK, we now know that a client is waiting, so next steps won't block:
clients.emplace_back(); // new client
if(listener.accept(clients.back()) != sf::Socket::Done)
{
// OK, something went wrong, current client us valueless...
clients.pop_back();
// adding and then removing? well, normally, this case here
// should not occur anyway, so we optimized for the far more
// common case.
}
else
{
// want to listen on as well
selector.add(clients.back());
}
}
for(auto& c : clients)
{
if(c.isReady())
{
// handle communication
}
}
Handling communinication is up to you... I wouldn't just communicate if at least two clients are connected. If you leave the messages from one single client unhandled, you might end up in needing to handle quite a bunch of outdated messages as soon as another client arrives, so I'd rather handle anything incoming immediately even with one single client. If it appears more appropriate to you, you might still place a if(clients.size() >= 2)
around the (range based) for loop.
If a client disconnects, don't forget to remove it from the selector! Having done so, you can safely remove it from the clients list as well.
Finally: the endless loop!
You might want to replace this via some conditional loop, checking if the server should still be running at all or not. You'd then yet need some mechanism to set this condition to false. There are different options for, e. g. some separate thread checking some specific input, signals (especially on POSIX systems), ...
Because you don't accept a second connection...
Changing code order a little:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
}
printf("Waiting for first connection...n");
while (clients.size() < 2)
{
sf::TcpSocket *socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
}
clients.push_back(socket);
// OK, that one would be printed twice!!!
printf("Waiting for second connection...n");
}
This won't be the final loop, though, it is just intended for demonstration.
Be aware that you don't delete the clients created anywhere (-> memory leak!). You might consider usage of smart pointers instead of raw pointers.
OK, so now: you want to accept arbitrary number of clients, and as soon as number you have more than two clients, run some application.
At very first, you need to continue accepting new clients on the loop (I changed the logging messages a little...:
std::vector<sf::TcpSocket*> clients;
sf::TcpListener listener;
if (listener.listen(SERVERPORT) != sf::Socket::Done)
{
printf("Errorn");
return; // no need to go on on error!
}
printf("start waiting for clients...n");
for(;;) // endless loop...
{
sf::TcpSocket* socket = new sf::TcpSocket;
if (listener.accept(*socket) != sf::Socket::Done)
{
printf("Errorn");
// TODO: consider some appropriate error handling
// minimally:
delete socket; // otherwise, you produce memory leaks!
}
clients.push_back(socket);
printf
(
"new client accepted; number of clients now: %llun"
"continue waiting...n",
clients.size()
);
// llu: most likely on 64-bit machine, on 32 bit either lu or u,
// depending on type of size_t; you get around having to decide
// if using C++ streams instead...
}
Problem now is: You additionally need to handle the connections appropriately! Have a look at this SFML tutorial, especially the section Blocking on a group of sockets. The selector described there is exactly what you need. Most important:
A selector can monitor all types of sockets: sf::TcpSocket, sf::UdpSocket, and sf::TcpListener.
So you can add all of your sockets and the listener to. You still have to maintain your instances yourself, though:
A selector is not a socket container. It only references (points to) the sockets that you add, it doesn't store them. There is no way to retrieve or count the sockets that you put inside. Instead, [...].
Well, you covered the 'instead' part already with your vector. Normally I'd recommend storing the objects in the vector directly; however, you cannot, as you need references to in the selector. So you need to store pointers in the vector – or you can use a std::list
instead, which won't invalidate references or pointers to stored data on insertion or deletion of objects (apart from pointers to the removed object itself, of course).
If you want to stay with the vector, you might consider using smart pointers, though, so that you don't have to care for memory management (e. g. std::vector<std::unique_ptr<sf::TcpSocket>> clients
).
I personally would prefer the std::list
:
std::list<sf::TcpSocket> clients; // notice: no pointers...
sf::TcpListener listener;
sf::SocketSelector selector;
selector.add(listener); // you want to listen as well...
for(;;)
{
// wait on selector as described in tutorial, I'd recommend only
// waiting for one second: you might want to handle the application
// exiting at some point of time!
}
If waiting was successful, you'd now first check the server socket, then the clients):
if(listener.isReady())
{
// OK, we now know that a client is waiting, so next steps won't block:
clients.emplace_back(); // new client
if(listener.accept(clients.back()) != sf::Socket::Done)
{
// OK, something went wrong, current client us valueless...
clients.pop_back();
// adding and then removing? well, normally, this case here
// should not occur anyway, so we optimized for the far more
// common case.
}
else
{
// want to listen on as well
selector.add(clients.back());
}
}
for(auto& c : clients)
{
if(c.isReady())
{
// handle communication
}
}
Handling communinication is up to you... I wouldn't just communicate if at least two clients are connected. If you leave the messages from one single client unhandled, you might end up in needing to handle quite a bunch of outdated messages as soon as another client arrives, so I'd rather handle anything incoming immediately even with one single client. If it appears more appropriate to you, you might still place a if(clients.size() >= 2)
around the (range based) for loop.
If a client disconnects, don't forget to remove it from the selector! Having done so, you can safely remove it from the clients list as well.
Finally: the endless loop!
You might want to replace this via some conditional loop, checking if the server should still be running at all or not. You'd then yet need some mechanism to set this condition to false. There are different options for, e. g. some separate thread checking some specific input, signals (especially on POSIX systems), ...
edited Nov 26 '18 at 11:25
answered Nov 23 '18 at 14:27
AconcaguaAconcagua
12.3k32143
12.3k32143
I've just tried your first solution and it's not really working. When I connect the first client, client.size() is equal to 2, even if I haven't connected my second client yet. Also, I don' really want exactly 2 clients, but at least 2...if that makes sense. It will be a matchmaking system...
– Koosshh56
Nov 23 '18 at 14:49
Also, I tried to increase the while condition thresholdclients.size() < 2
to 10, and it counts one connection as 3...so the clients.size() increases by 3 every time I connect a client
– Koosshh56
Nov 23 '18 at 14:55
any help with this? I'm still stuck. Thanks
– Koosshh56
Nov 26 '18 at 9:19
@Koosshh56 Without seing your changed code, a bit difficult to guess the issues... I modified this answer, though, so it (hopefully) covers your needs better.
– Aconcagua
Nov 26 '18 at 11:18
add a comment |
I've just tried your first solution and it's not really working. When I connect the first client, client.size() is equal to 2, even if I haven't connected my second client yet. Also, I don' really want exactly 2 clients, but at least 2...if that makes sense. It will be a matchmaking system...
– Koosshh56
Nov 23 '18 at 14:49
Also, I tried to increase the while condition thresholdclients.size() < 2
to 10, and it counts one connection as 3...so the clients.size() increases by 3 every time I connect a client
– Koosshh56
Nov 23 '18 at 14:55
any help with this? I'm still stuck. Thanks
– Koosshh56
Nov 26 '18 at 9:19
@Koosshh56 Without seing your changed code, a bit difficult to guess the issues... I modified this answer, though, so it (hopefully) covers your needs better.
– Aconcagua
Nov 26 '18 at 11:18
I've just tried your first solution and it's not really working. When I connect the first client, client.size() is equal to 2, even if I haven't connected my second client yet. Also, I don' really want exactly 2 clients, but at least 2...if that makes sense. It will be a matchmaking system...
– Koosshh56
Nov 23 '18 at 14:49
I've just tried your first solution and it's not really working. When I connect the first client, client.size() is equal to 2, even if I haven't connected my second client yet. Also, I don' really want exactly 2 clients, but at least 2...if that makes sense. It will be a matchmaking system...
– Koosshh56
Nov 23 '18 at 14:49
Also, I tried to increase the while condition threshold
clients.size() < 2
to 10, and it counts one connection as 3...so the clients.size() increases by 3 every time I connect a client– Koosshh56
Nov 23 '18 at 14:55
Also, I tried to increase the while condition threshold
clients.size() < 2
to 10, and it counts one connection as 3...so the clients.size() increases by 3 every time I connect a client– Koosshh56
Nov 23 '18 at 14:55
any help with this? I'm still stuck. Thanks
– Koosshh56
Nov 26 '18 at 9:19
any help with this? I'm still stuck. Thanks
– Koosshh56
Nov 26 '18 at 9:19
@Koosshh56 Without seing your changed code, a bit difficult to guess the issues... I modified this answer, though, so it (hopefully) covers your needs better.
– Aconcagua
Nov 26 '18 at 11:18
@Koosshh56 Without seing your changed code, a bit difficult to guess the issues... I modified this answer, though, so it (hopefully) covers your needs better.
– Aconcagua
Nov 26 '18 at 11:18
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53448141%2fsfml-detect-multiple-connections-to-server-and-count-them%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown