Reputation: 1349
I have created a server and client in C++ and I want them to connect to each other while they are on the same network, but running on different machines. I am currently using the following code to get the server to connect to the network:
#define HOST_PORT "27015"
WSADATA wsaData;
int status;
struct addrinfo * data;
struct addrinfo hints;
WSAStartup(MAKEWORD(2, 2), &wsaData);
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_IP;
hints.ai_flags = AI_PASSIVE;
char hostname[1024];
hostname[1023] = '\0';
gethostname(hostname, 1023);
if (getaddrinfo(hostname, HOST_PORT, &hints, &data))
{
std::cout << "Unable to translate host name to address\n";
WSACleanup();
return 1;
}
The client attempts to connect using similar code:
#define DEFAULT_PORT "27015"
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char hostname[1024];
hostname[1023] = '\0';
gethostname(hostname, 1023);
struct addrinfo *result = NULL;
int iResult = getaddrinfo(hostname, DEFAULT_PORT, &hints, &result);
if (iResult != 0)
{
std::cout << ("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return false;
}
This works fine when the client and server are on the same machine, but how do I allow them to connect when they are on separate machines? I expect that I need the client to connect to the same host name when using gettaddrinfo()
, but how do I get the host name of the server? (e.g. If hostname
on the server becomes "InsertNameHere", how do I allow the client to detect "InsertNameHere" and use it as the first parameter in getaddrinfo()
?)
Upvotes: 2
Views: 2343
Reputation: 21936
Your problem is fairly common, and there’re several approaches to this.
Manual Configuration
For example, your server might find out it’s IP4 address, print it to the console, then you somehow manually specify that address in your client app, e.g. as a command-line parameter, or in some configuration file.
This is the most developer-friendly, and least user-friendly, way.
Service Publishing
Your server may register itself on startup to some place from where the clients may read. People usually implement this method in enterprise Windows environments, where the Active Directory is that “some place”. If this is your case, see this article for the WinSock APIs you need.
Service Discovery
Or, you may implement a discovery mechanism yourself, for example using UDP broadcasts.
In your server, listens on some UDP port, wait for some discover datagram, and respond with some “discovered OK” datagram.
In your client, on startup, send a discover UDP datagram to the broadcast address to that UDP port number. If there’re your server[s] running on the same subnets where the client is, the client will receive the “discovered OK” message[s]. If there’s just one response, you know there’s a single accessible server, and you can connect right away. If there’re several responses, it could mean there’re multiple servers, you can ask user where to connect.
This approach is relatively hard to implement correctly (e.g. UDP offers no guaranteed delivery so retries and timeouts are needed), however it’s the most user friendly way. If you ever played old LAN games like Quake, that’s how they discover their servers.
I'd like to add there're third-party libraries that you could use, such as Collage and ReplicaNet, however I don’t have a hands-on experience with those, can’t recommend any of them.
Upvotes: 2
Reputation: 1011
To connect to remote server you need to obtain it's IP address or hostname. The default approach is either to manually pass it as a parameter or to use naming services like ZooKeeper (see wiki)
The easiest and best way is to configure your network and use DNS instead of direct IPs (for example myserver1.mycompany.com:27015 where 27015 is a TCP port).
Upvotes: 1