c++ - Server won't connect to more than one client? -
the problem connects 1 client instead of two. can me figure out why?
server:
#include <sfml/system.hpp> #include <sfml/network.hpp> #include <iostream> void sendinfo(void *userdata) { sf::ipaddress* ip = static_cast<sf::ipaddress*>(userdata); // print something... while(true){ // create udp socket sf::socketudp socket; // create bytes send char buffer[] = "sending info."; // send data "192.168.0.2" on port 4567 if (socket.send(buffer, sizeof(buffer), *ip, 4444) != sf::socket::done) { // error... } } } void receiveinfo(void *userdata) { // print something... while(true){ // create udp socket sf::socketudp socket; // bind (listen) port 4567 if (!socket.bind(4444)) { // error... } char buffer[128]; std::size_t received; sf::ipaddress sender; unsigned short port; if (socket.receive(buffer, sizeof(buffer), received, sender, port) != sf::socket::done) { // error... } // show address / port of sender std::cout << buffer << std::endl; socket.close(); } } int main() { sf::ipaddress client[2]; int connected = 0; while(connected < 2){ // create udp socket sf::socketudp socket; // bind (listen) port 4567 if (!socket.bind(4444)) { // error... } char buffer[128]; std::size_t received; sf::ipaddress sender; unsigned short port; if (socket.receive(buffer, sizeof(buffer), received, sender, port) != sf::socket::done) { // error... } // show address / port of sender client[connected] = sender; socket.close(); sf::thread* send = new sf::thread(&sendinfo, &client[connected]); sf::thread* receive = new sf::thread(&receiveinfo, &client[connected]); // start ! send->launch(); receive->launch(); connected++; } while(true){ } return exit_success; }
client:
#include <sfml/system.hpp> #include <sfml/network.hpp> #include <iostream> void sendinfo(void *userdata) { // print something... while(true){ // create udp socket sf::socketudp socket; // create bytes send char buffer[] = "client sending info."; // send data "192.168.0.2" on port 4567 if (socket.send(buffer, sizeof(buffer), "127.0.0.1", 4444) != sf::socket::done) { // error... } } } void receiveinfo(void *userdata) { // print something... while(true){ // create udp socket sf::socketudp socket; // bind (listen) port 4567 if (!socket.bind(4444)) { // error... } char buffer[128]; std::size_t received; sf::ipaddress sender; unsigned short port; if (socket.receive(buffer, sizeof(buffer), received, sender, port) != sf::socket::done) { // error... } // show address / port of sender std::cout << buffer << std::endl; socket.close(); } } int main() { // create udp socket sf::socketudp socket; // create bytes send char buffer[] = "client joined."; // send data "192.168.0.2" on port 4567 if (socket.send(buffer, sizeof(buffer), "127.0.0.1", 4444) != sf::socket::done) { // error... } sf::thread* send = new sf::thread(&sendinfo); sf::thread* receive = new sf::thread(&receiveinfo); // start ! send->launch(); receive->launch(); while(true){ } return exit_success; }
first things first: chat server or 'more typical' server?
if chat server, either need have list of sockets connected clients (you can connect udp sockets using connect()
call, convenient, , helps reduce chances of spoofed peers) or list of client addresses can supply sendto()
or sendmsg()
.
more 'typical' servers won't try send messages client except 1 made request: servers typically don't save anything clients, , instead use recvfrom()
or recvmsg()
peer's address use in later sendto()
or sendmsg()
calls.
also, protocols rely on 1 well known port; server uses 1 specific port convention, clients select whatever port open , free. ftp relies heavily on well-known ports on client-side well, , result gigantic pain tunnel through network address translation firewalls.
it isn't academic: both client and server attempting bind()
port 4444
. means need @ least two ip addresses on single machine test, or use virtualization software run entirely separate machine on same hardware, or have 2 machines available. it's more work needs be, , there's no reason clients care local port numbers:
server:
// bind (listen) port 4567 if (!socket.bind(4444)) { // error... }
client:
// bind (listen) port 4567 if (!socket.bind(4444)) { // error... }
poof! these 2 never run on same host without significant tricks. expect "it connects one" server or client connecting itself, without code fill in // error
blocks, it'd tough tell sure.
(and while we're here, i'd take aside talk comments; comments re-state code aren't useful. you'll note of comments in fact wrong, referring wrong ips or ports. don't add information:
// create udp socket sf::socketudp socket;
i know we're taught add comments, sadly we're not taught kind of comments add. comment in both programs i'd recommend keeping one, amended:
// udp doesn't require listen or accept if (!socket.bind(4444))
it isn't obvious reading code, , won't wrong when port number read out of environment variable, command line parameter, configuration file, or registry. (it might redundant in team of people familiar sockets api, might gold programmer not familiar differences between udp , tcp.)
good function names, variable names, etc., win on comments every time. end of aside. :)
and now, more minor nit-picking: thread handlers doing tasks this:
while(1) { socket s; bind s; r = recv s; print r; close s; }
this needless creation, binding, , closing, wasted energy, both computer's energy , (much more importantly) your energy. consider following 2 re-writings:
recv_thread() { socket s; bind s; while (1) { r = recv s; print r; } close s; }
or
recv_thread(s) { while (1) { r = recv s; print r; } } /* ... */ socket s; bind s; sf::thread* rt = new sf::thread(&recv_thread); rt->launch(s);
the first option simple refactoring of existing code; keeps socket creation , destruction in thread function, moves loop invariants out of loop. code inside loop necessary.
the second option more drastic reworking: moves socket creation main thread, error-handling much easier, , thread function remote peer needs thread do. (if wanted change udp tcp, second option far easier easier 1 change -- threading code might not need modifications @ all.)
i hope helps. :)
Comments
Post a Comment